import React from 'react'
import ReactDom from 'react-dom'
let el=<h1><span>hello</span><span>wrold</span></h1>
console.log(el)
ReactDom.render(el,window.root);
複製代碼
function createElement(type,props,children){
let obj={};
obj.type=type;
obj.props={};
obj.props.children=null;
for(let key in props){
obj.props[key]=props[key]
}
children.forEach(child => {
let {type,props,subchildren} = child
obj.props.children.push(createElement(type,props,subchildren))
})
return obj
}
複製代碼
3. ReactDom.render(vnode,root)會將其渲染出到頁面root中:
4. ReactDom.render原理簡析:
function render(vnode,container){
if(typeof vnode ==='string') return container.appendChild(document.createTextNode(vnode));
let{type,props} = vnode;
let tag = document.createElement(type);
for(let key in props){
if(key==='children'){
Array.from(props[key]).forEach(child => {
render(child,tag)
});
}else{
tag.setAttribute(key,props[key]);
}
}
container.appendChild(tag);
}
複製代碼
import React from 'react'
import ReactDom from 'react-dom'
function test(){
let state = {
title:'標題',
context:'內容'
}
return (
<div>
<h3>{state.title}</h3>
<p>{state.context}</p>
</div>
)
}
ReactDom.render(
<div>
{test()}
{test()}
{test()}
</div>,window.root);
複製代碼
import React from 'react'
import ReactDom from 'react-dom'
function Test(props){
let state={
title:"標題"
}
return (
<div>
<h3>{state.title}</h3>
<p>{props.context}</p>
</div>
)
}
ReactDom.render(
<div>
<Test context='123'></Test>
<Test context='456'></Test>
<Test context='789'></Test>
</div>,window.root);
複製代碼
函數聲明組件存在一些問題:html
類組件消除了函數聲明組件的問題,也是如今寫react的正常語法。node
import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
import PropTypes from 'prop-types'; //屬性校驗插件
class Clock extends Component {
state = {
time: new Date().toLocaleString()
}
static propTypes = {
name: PropTypes.string.isRequired //name必填,校驗是否填寫name屬性
}
// 組件掛載後調用
componentDidMount() {
this.timer = setInterval(() => {
// 只會覆蓋之前的屬性相似 Object.assign()
this.setState({ time: new Date().toLocaleString() })
}, 1000)
}
handleClick = () => { //箭頭函數,this用最外層的this,指向當前組件
ReactDOM.unmountComponentAtNode(window.root)
}
// 組件卸載前調用,通常用於解綁事件和方法
componentWillUnmount() {
clearInterval(this.timer)
}
// 默認渲染這個組件會調用render方法
// 只是在上面函數式聲明基礎上包了一層函數,這樣能夠控制其執行時間,添加聲明週期
render() {
let {name} = this.props //通常會解構props
return <div>
{name} <span>{this.state.time}</span>
<button onClick={this.handleClick}>刪除</button>
</div>
}
}
render(<Clock name='test-clock'/>, window.root);
複製代碼
// React16.3 推出了新的聲明週期
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Counter extends Component {
static defaultProps = {
a: 1
}
state = {
num: 0
}
constructor(props) {
console.log('parent-constructor')
super();
}
// react16.3中標識了這個方法會被廢棄掉
// 後期有須要的話 能夠放在constructor中替代掉
componentWillMount() {
console.log('parent-componentWillMount');
}
// react的性能優化 immutablejs
shouldComponentUpdate(){
console.log('parent-shouldComponentUpdate');
return true
}
componentWillReceiveProps(){
console.log('parent-componentWillReceiveProps');
}
componentWillUpdate(){
console.log('parent-componentWillUpdate');
}
componentDidUpdate() {
console.log('parent-componentDidUpdate');
}
handleClick = () => {
this.setState({ num: this.state.num + 0 });
}
render() {
console.log('parent-render');
return <div>
<button onClick={this.handleClick}>+</button>
{this.state.num}
<ChildCounter n={this.state.num}></ChildCounter>
</div>
}
componentDidMount() {
console.log('parent-didmount');
}
componentWillUnmount() {
console.log('parent-組件卸載')
}
}
class ChildCounter extends Component{
componentWillMount(){
console.log('child-componentWillMount')
}
render(){
console.log('child-render');
return <div>child counter {this.props.n}</div>
}
componentDidMount() {
console.log('child-componentDidMount')
}
shouldComponentUpdate(){
console.log('child-shouldComponentUpdate');
return true
}
componentWillUpdate(){
console.log('child-componentWillUpdate');
}
componentDidUpdate() {
console.log('child-componentDidUpdate');
}
//16.3中這個方法廢棄了
componentWillReceiveProps(){
console.log('child-componentWillReceiveProps');
}
}
ReactDOM.render(<Counter></Counter>, window.root);
複製代碼
import React,{Component} from 'react';
import {render} from 'react-dom';
class UnControl extends Component{
b = React.createRef(); // 16.3的api React.createRef()
handleClick = () =>{
alert(this.a.value); // 寫法1
alert(this.b.current.value) // 寫法2
}
render(){
return (<div>
<input type="text" id="username" ref={dom=>this.a=dom}/>
<input type="text" id="password" ref={this.b}/>
<button onClick={this.handleClick}>點擊</button>
</div>)
}
}
render(<UnControl></UnControl>,window.root);
複製代碼
import React from 'react';
import ReactDOM from 'react-dom';
class Control extends React.Component{
state = {
a:'hello',
b:'world'
}
changeHandler = (e)=>{
let val = e.target.name
this.setState({
[val]:e.target.value
})
}
render(){
return (
<div>
{this.state.a}
{this.state.b}
<input type="text" name="a" value={this.state.a} onChange={this.changeHandler}/>
<input type="text" name="b" value={this.state.b} onChange={this.changeHandler}/>
</div>
)
}
}
ReactDOM.render(<Control></Control>,window.root);
複製代碼
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Second1 from './Second1';
import Second from './Second';
class App extends Component {
state = {
count:0
}
handleCountChange = (num)=>{
this.setState({count:num})
}
render(){
return(
<div>
<Second count={this.state.count}></Second>
<Second1 count={this.state.count} countChange={this.handleCountChange}></Second1>
</div>
)
}
}
ReactDOM.render(<App></App>, window.root);
複製代碼
//second.js
import React, { Component } from 'react'
export default class Second extends Component {
render() {
let {count} = this.props
return (
<div>{count}</div>
)
}
}
複製代碼
//second1.js
import React, { Component } from 'react'
import Third from './Third';
export default class Second1 extends Component {
render() {
let {count,countChange} = this.props
return (
<Third num={count} numChange={countChange}></Third>
)
}
}
複製代碼
//third.js
import React, { Component } from 'react';
export default class Third extends Component {
handleClick =()=>{
console.log(this.props.num+1);
this.props.numChange(this.props.num+1);
}
render(){
return (
<span onClick={this.handleClick}>+</span>
)
}
}
複製代碼
import React, { Component } from 'react';
import {Provider} from './context';
import ReactDOM from 'react-dom';
import Second1 from './Second1';
import Second from './Second';
class App extends Component {
state = {
count:0
}
handleCountChange = (num)=>{
this.setState({count:num})
}
render(){
return(
// 提供一個contex,上面掛載了全局狀態
<Provider value={{numChange:this.handleCountChange,num:this.state.count}}>
<Second></Second>
<Second1></Second1>
</Provider>
)
}
}
ReactDOM.render(<App></App>, window.root);
複製代碼
// context.js
import React from 'react';
let { Provider, Consumer } = React.createContext(); //react提供的API
export {Provider,Consumer}
複製代碼
// second.js
import React, { Component } from 'react';
import {Consumer} from './context';
export default class Second extends Component {
render() {
return (
<Consumer>
{(value)=>{
return <div>{value.num}</div>
}}
</Consumer>
)
}
}
複製代碼
// second1.js
import React, { Component } from 'react'
import Third from './Third';
export default class Second1 extends Component {
render() {
return (
<Third></Third>
)
}
}
複製代碼
//third.js
import React, { Component } from 'react';
import {Consumer} from './context';
export default class Third extends Component {
render(){
return (<Consumer>
{(value)=>{ //固定語法value就是Provider中的value
return <span onClick={()=>{value.numChange(value.num + 1)}}>+</span>
}}
</Consumer>)
}
}
複製代碼
我的使用一種框架時總有一種想知道爲啥這樣用的強迫症,否則用框架用的不舒服,不要求從源碼上知道其原理,可是必須得從心理上說服本身。react