<div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> /* new Vue({ el:"#app" data:{ msg:' } }) Vue实例的生命周期: 1 创建Vue实例,初始化生命周期钩子函数 2.数据舰艇,初始化methods/computed 数据监听前调用beforeCreate钩子,数据监听后调用created钩子 3.获取模板,编译模板,模板编译完成后会将所编译的模板挂在到真实DOM中,用render函数生成虚拟DOM, 挂着在前会回调beforeMount钩子,挂在后会回调mounted钩子函数 //上面为挂载阶段 4.数据更新,导致视图更新 视图更新前会回调beforeUpdate钩子,在视图更新后会回调updated钩子 //更新阶段 5.销毁(当调用$destroy()方法) 销毁前会调用beforeDestory钩子,销毁后会回调destoryed钩子 //销毁阶段 1.beforeCreate/created 2. beforeMount/mounted 3. beforeUpdata/updated 4. beforeDestory/destoryed */ class App extends React.Component{ constructor(props){ super(props) console.log('App的构造函数被调用了...') this.state={ person:{}, //要改person值可以在componentWillMount里,也可以在DidMount里用setState改变,setState会再次更新视图 content:'aaa' } } componentWillMount(){ //组件即将挂在的声明周期钩子函数,相当于Vue中beforeMount钩子 console.log('App即将挂载。。。componentWillMount') this.setState({ content:'bbb' }) } componentDidMount(){ console.log('App挂载完成了....componentDidMount') this.setState({ content:'ccc' }) } render(){ console.log('App组件挂载。。。render函数被调用了....') return( <div> <h1>{this.props.title}</h1> <p>{this.state.content}</p> <button onClick={this.changeState.bind(this)}>修改状态</button> </div> ) } changeState(){ this.setState({//自动触发shouldComponentUpdate调用 content:'ddd' }) } shouldComponentUpdate(nextProps,nextState){ console.log('App组件应该更新了。。。。shouldComponentUpdate') //第一个参数是当前最新的属性对象 //第二个参数是当前 组件最新的状态对象 //返回值为boolean,true(表示即将更新视图,接下来会调用render函数) //false(表示不更新视图,生命周期从这里终止) return true//默认返回true 只有挂载完成后,也就是回调完4个钩子函数后,再运行了setState或别的更新的时候才会促发这个海曙,componentDidMount里的setState还是有效的,但是DidMount就无效了,因为DidMount是已经完成了加载再去setState,这时候的setState就是去更新了 //return false 不会去调用render了 this.setState会自动出发shouldComponentUpdate } componentWillUpdate() { console.log('App组件即将更新....componentWillUpdate') } componentDidUpdate(prevProps,prevState){ console.log('App组件已经更新完成...componentDidUpdate') } } ReactDOM.render(<App title="hello,world"/>,document.getElementById('root')) /*挂载阶段 4个函数调用 1.调用组件的构造函数,实例化一个对象,上面class App只是一个声明,只有被调用了才会去实例化 ReactDOM.render的时候,有人去调用App,这时候生命周期才开始,如果调用两次<App/>就有两次App生命周期, 首先做的就调用构造函数,实例化App,同时会把App上的属性传过去 const app=new App({title:"hello world"}) //得到一个对象--》组件对象 2.组件挂在前会回调componentWillMount() app.componentWillMount() 3.调用render函数渲染页面,挂在组件 app.render() 得到JSX标签,用react.createElement得到DOM描述对象,然后进行比较diff算法,然后渲染到真DOM //{tyoe:'div',props:{children:[{type:'h2}]}} 在react中维持了一个内存中的虚拟DOM描述对象, render函数被调用后返回的是DOM的描述对象,React会将本次render函数返回的描述对象进行对比 比较出两个对象的不同然后以最快的速度去更新真实DOM //只有用render才会有视图更新 4.挂载后,React会回调componentDidMount()钩子函数 //上面4步相当于就挂载完成了 更新阶段---分两种 默认也是4个回调函数 componentShouldUpdate---componentWillUpdate---render---componentDidUpdate 一种是自身数据更新,还有一种可能是父组件数据导致更新。事例中的title是父组件里的title属性传过来的,如果title值变了视图也会更新 第一种更新:子组件自身状态变化导致视图更新 5.当用户调用setState时,促发shouldComponentUpdate调用 如果shouldComponentUpdate返回值为true(默认即为true),则会更新视图,如果返回false则不会更新视图 6.更新视图前会回调componentWillUpdate() 7.调用render函数,更新视图 8.更新完成,会回调componentDidUpdate //第二种,父子间的render函数调用导致视图更新 5.调用子组件的compoentnWillReceiveProps函数 6.调用shouldComponentUpdate钩子函数 7.如果shouldComponentUpdate返回true,则调用componentWillUpdate,否则终止 8.调用render函数,更新视图 9.更新完成,会回调componentDidUpdate 卸载, 10.调用componentWillUnmount钩子函数 函数式组件没有生命周期,React.createClass组件没有构造函数,其他都一样,它不是用constructor构造函数来初始化,只有挂载的初始化阶段不同,而是用 getInitialState(){ return{ //初始状态 } } 以及getDefalutProps方法(初始化属性) */ //优化:shouldComponentUpdate这个函数可以优化,减少子组件render次数,减少没必要的调用 </script>
06-组件的生命周期--父子组件
<div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> class App extends React.Component{ constructor(props){ super(props) this.state={ content:'初始化的content内容' } console.log('父组件App的构造函数被调用了') } componentWillMount() { console.log('父组件App即将挂载。。。。componentWillMount') } changeContent=()=>{ this.setState({ content:'修改后的conten内容' }) } render(){ console.log('父组件App的render函数....') return ( <div> <p>App组件的状态:{this.state.content}</p> <button onClick={this.changeContent}>修改App的content状态</button> <hr/> <Child myContent={this.state.content} /> </div> ) } componentDidMount(){ console.log('父组件App挂载完成。。。。componentDidMount') } shouldComponentUpdate(nextProps,nextState){ console.log('父组件shouldComponentUpdate被调用') return true } componentWillUpdate() { console.log('父组件的即将更新...componentWillUpdate') } componentDidUpdate(prevProps,prevState) { console.log('父组件更新完成....componentDidUpdate') } componentWillReceiveProps(nextProps){ //这个函数被调用是有条件的:被某组件(父组件)的子组件,只要某组件更新了,那么子组件就会促发这个钩子函数,不管有没有传值过来。所以一般来说也只有最外层的App不会触发到这个函数,因为它是顶级组件 //当前父组件的render函数被调用后自动会回调子组件的该生命钩子函数 console.log('父组件Child的componentWillReceiveProps被调用....') } componentWillUnmount() { console.log('父组件即将卸载....componentWillUnmount') } } class Child extends React.Component{ //子组件的生命周期 //挂载阶段 constructor(props){ super(props) console.log('子组件Child的构造函数被调用了') this.title="hello" //普通数据 } componentWillMount() { console.log('子组件Child即将挂载。。。。componentWillMount') } render(){ console.log('子组件Child的render函数....') return ( <div> <p>子组件获取到的父组件属性:{this.props.myContent}</p> <h3>子组件的普通数据:{this.title}</h3> <button onClick={this.changeTitle}></button> </div> ) } this.changeTitle=()=>{ this.title="zhangsan" this.forceUpdate() //强制更新视图 } componentDidMount(){ console.log('子组件Child挂载完成。。。。componentDidMount') } //更新阶段 如果是自己的一个setState,就会进入shouldComponentUpdate 这个一旦显示写出来就要返回true,否则就终止了 //相较于修改自身的setState更新多了一个回调函数componentWillReceiveProps,这个函数用于接收父组件传过来的props发生变化时用的,如果父组件传过来的props发生了变化,那么首先进入componentWillReceiveProps componentWillReceiveProps(nextProps){ //当前父组件的render函数被调用后自动会回调子组件的该生命钩子函数 console.log('子组件Child的componentWillReceiveProps被调用....') //不管父组件是否有props传递给子组件,只要父组件的模板使用子组件 //则更新时父组件的render调用一次都会自动导致子组件的componentWillReceiveProps调用 } shouldComponentUpdate(nextProps,nextState){ console.log('子组件shouldComponentUpdate被调用。。。') return true } componentWillUpdate() { console.log('子组件的即将更新...componentWillUpdate') } componentDidUpdate(prevProps,prevState) { console.log('子组件更新完成....componentDidUpdate') } //卸载 componentWillUnmount() { console.log('子组件即将卸载....componentWillUnmount') } } //上面定义好了,真正的路口在下面,ReactDOM.render ReactDOM.render(<App title="hello,world"/>,document.getElementById('root')) //进入App---首先实例化App进入后调用componentWillMount()然后render(),,这时候碰到child组件,会先进去实例化Child组件,调用Child的componentWillMount,render(),compoentDidMount,然后再回来调用父组件的componentDidMount //卸载组件 setTimeout(()=>{ //解绑组件 ReactDOM.unmountComponentAtNode(document.getElementById('root')) }) </script>