Open Sunshine168 opened 6 years ago
每日,每一段时间都在问自己自己干了什么,看一下自己知道什么,希望在不断进步的时候,不断更新。
PS:概念自问自答只是精炼我自己的看法,有不对请大家不吝指出。
写一下react的组件的生命周期吧
加载期
constructor() componentWillMount() render() componentDidMount()
更新期
componentWillReceiveProps() shouldComponentUpdate() componentWillUpdate() render() componeneDidUpdate()
销毁期
componentWillUnmout()
错误捕捉
componentDidCatch()
不要调用setState的生命周期
shouldComponentUpdate() componentWillUpdate() // 这个周期是不能调用 会造成死循环 componentWillUnmount()
将生命周期函数声明为async会对组件有影响吗?
没有,函数内部可以使用 async/await 的语法糖。
为什么可以将生命周期函数声明为async function
因为即使是声明为 async 在调用的时候也是当成普通函数调用。
综合应用一下
main.js
import React from 'react'; import { render } from 'react-dom'; import Parent from './parent'; const styles = { fontFamily: 'sans-serif', textAlign: 'center', }; class App extends React.Component { state = { mount:true } render(){ return ( <div style={styles}> {this.state.mount?<Parent />:null} <h2>Start editing to see some magic happen {'\u2728'}</h2> <button onClick={()=>{ this.setState({ mount:!this.state.mount }) }}>test</button> </div> ) } } render(<App />, document.getElementById('root'));
parent.js
import React from 'react'; import ChildComponent from './child.js' export default class Parent extends React.Component { constructor(props) { super(props) console.log('parent:constructor') } componentWillMount() { console.log('parent: will mount') } componentDidMount() { console.log('parent: did mount') } componentDidUpdate() { console.log('parent: did update') } componentWillUnmount() { console.log('parent: will mount') } render() { console.log('parent render') return ( <div> <ChildComponent refresh={()=>{ console.log('did update A') this.setState({},()=>{ console.log('did update B') }) }}/> </div> ) } }
child.js
import React from 'react'; export default class extends React.Component{ constructor(props){ super(props) console.log('child:constructor') } componentWillMount(){ console.log('child: will mount') } componentDidMount(){ console.log('child: did mount') } componentDidUpdate(){ console.log('child: did update') } componentWillUnmount(){ console.log('child: will mount') } render(){ console.log('child render') return ( <div> <span>child Component </span> <button onClick={() => { this.props.refresh() }}>refresh</button> </div> ) } }
题一、请问在 App 第一次render的时候,控制台输出的语句是什么?
parent:constructor parent: will mount parent render child:constructor child: will mount child render child: did mount parent: did mount
题二、请问在点击子组件refresh按钮按下的时候控制台输出的语句是什么?
did update A parent render child render child: did update parent: did update did update B
题三、请问在第一次点击test按钮的时候控制台会输出什么?
parent: will mount child: will mount
引出,为什么是这样的顺序?
解析virtual Dom的时候是递归的形式
组件更新是自顶向下。
TODO // 实现一下一个简单的virtual Dom 解析
异步。
0,0,2,3。
生命周期内合并执行,合并执行就是将其并在一个事务中进行,进行批量更新。
import React from "react"; export default class App extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); this.setState({ count: this.state.count + 1 }); console.log(this.state.count); setTimeout(() => { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); this.setState({ count: this.state.count + 1 }); console.log(this.state.count); }); } render() { return <div>{this.state.count}</div>; } }
延伸,为什么setState需要是异步的,举个例子?
class Parent extends React.Component{ state = { a:1 } render(){ <Child a={this.state.a} increase={()=>{this.setState({ a:this.state.a +1 })}}/> } }
在同步的情况下 setState 以后父组件的a是2,但是在更新组件前props到子组件的a却还是1 这样是不合理的
setState
具体见 why setState is async
PureComponent 和 Stateless Componet的区别:
前者可以具有自身的state,有组件的生命周期,后者不具备。 PureCompoent 在shouldComponentUpdate 上面进行简单的浅比较,不适合用于处理复杂状态。 Stateless Component本身没有更新机制,只能通过父组件更新。
redux的三大组成
action,store,reducer
redux的三大原则,讲讲了解。
单一数据源,数据只能通过action修改,reducer必须是纯函数。
单一数据源指的是,全部的store应该挂载在一颗store上。
总结起来就是单向数据流
redux本身是不支持异步数据流的,即在没有中间件的时候dispatch的必须是一个Object(目前的理解是原型链的继承自Object)
你了解处理异步action的中间件
redux-thunk
短小精悍的中间件
const INCREMENT_MONEY = 'INCREMENT_MONEY' const mapDispatchToProps = (dispatch)=>({ getMoney:()=>{ setTimeout(()=>{ dispatch({ type:INCREMENT, }) },500) } }) // ...
redux-saga
适合处理比较复杂的异步问题,一些简单场景也提供便利的功能,saga中运行的任务是可取消的,像触发同一个任务的时候可以通过saga的机制总是执行最新的任务。
...
因为在遍历store中的key的时候,判断前后状态是通过浅比较。
通过observable包裹变量,通过Object.defineProperty重写get/set,通过atom发送信号到mobx中去。
更新机制,通过observer进行绑定组件。在绑定中通过reaction在render中收集依赖,再mobx收到依赖发送的信号的时候向绑定的组件发送更新信号,observer作为高阶组件再调用容器组件的forceUpdate 达到更新组件的目的。
实质,数据双向绑定。
import React from "react"; export default class App extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { this.refBtn.addEventListener("click", this.onClick); } componentWillUnmount() { this.refBtn.removeEventListener("click", this.onClick); } onClick = () => { console.log("before setState", this.state.count); this.setState(state => ({ count: state.count + 1 })); console.log("after setState", this.state.count); }; render() { return ( <div> <button onClick={this.onClick}>React Event</button> <button ref={ref => (this.refBtn = ref)}>Direct DOM event</button> </div> ); } }
. So it is just easier from the maintenance point of view to extract action creators into separate functions.
Detail
https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux
https://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559
更正两个地方。 第一个地方是,生命周期执行的顺序,在constructor的时候 确实是跟virtual dom的解析有关系, 更深入的讲,后面相关生命周期的执行顺序是由于render的递归。 这点迟点会结合源码深入看一下。
第二个地方是关于setState 因为props的传递是异步的(组件更新才会更新Props) setState的异步性正是保证了这种安全。 这里依然不是很明确,需要进一步思考。
每日,每一段时间都在问自己自己干了什么,看一下自己知道什么,希望在不断进步的时候,不断更新。
PS:概念自问自答只是精炼我自己的看法,有不对请大家不吝指出。
react基础
生命周期
写一下react的组件的生命周期吧
加载期
更新期
销毁期
错误捕捉
不要调用setState的生命周期
将生命周期函数声明为async会对组件有影响吗?
没有,函数内部可以使用 async/await 的语法糖。
为什么可以将生命周期函数声明为async function
因为即使是声明为 async 在调用的时候也是当成普通函数调用。
综合应用一下
main.js
parent.js
child.js
题一、请问在 App 第一次render的时候,控制台输出的语句是什么?
题二、请问在点击子组件refresh按钮按下的时候控制台输出的语句是什么?
题三、请问在第一次点击test按钮的时候控制台会输出什么?
引出,为什么是这样的顺序?
解析virtual Dom的时候是递归的形式组件更新是自顶向下。
TODO // 实现一下一个简单的virtual Dom 解析
setState
setState 是异步还是同步,下面的输出结果是什么,为什么?
异步。
0,0,2,3。
生命周期内合并执行,合并执行就是将其并在一个事务中进行,进行批量更新。
setState的第二个参数有什么用?
延伸,为什么setState需要是异步的,举个例子?
在同步的情况下setState
以后父组件的a是2,但是在更新组件前props到子组件的a却还是1 这样是不合理的具体见 why setState is async
组件
PureComponent 和 Stateless Componet的区别:
前者可以具有自身的state,有组件的生命周期,后者不具备。 PureCompoent 在shouldComponentUpdate 上面进行简单的浅比较,不适合用于处理复杂状态。 Stateless Component本身没有更新机制,只能通过父组件更新。
状态管理
redux
redux的三大组成
action,store,reducer
redux的三大原则,讲讲了解。
单一数据源,数据只能通过action修改,reducer必须是纯函数。
单一数据源指的是,全部的store应该挂载在一颗store上。
总结起来就是单向数据流
关于redux中的异步数据流
redux本身是不支持异步数据流的,即在没有中间件的时候dispatch的必须是一个Object(目前的理解是原型链的继承自Object)
你了解处理异步action的中间件
redux-thunk
短小精悍的中间件
redux-saga
适合处理比较复杂的异步问题,一些简单场景也提供便利的功能,saga中运行的任务是可取消的,像触发同一个任务的时候可以通过saga的机制总是执行最新的任务。
...
为什么reducers需要纯函数?
因为在遍历store中的key的时候,判断前后状态是通过浅比较。
mobx
通过observable包裹变量,通过Object.defineProperty重写get/set,通过atom发送信号到mobx中去。
更新机制,通过observer进行绑定组件。在绑定中通过reaction在render中收集依赖,再mobx收到依赖发送的信号的时候向绑定的组件发送更新信号,observer作为高阶组件再调用容器组件的forceUpdate 达到更新组件的目的。
实质,数据双向绑定。
拓展阅读
Why do we need middleware for async flow in Redux?
Detail
https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux
https://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559