每日,每一段时间都在问自己自己干了什么,看一下自己知道什么,希望在不断进步的时候,不断更新。
这是将近大半年的第一次react自测。
PS:有些概念自问自答只是精炼我自己的看法,有不对请大家不吝指出。
react基础
生命周期
写一下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 解析
setState
setState 是异步还是同步,下面的输出结果是什么,为什么?
异步。
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的第二个参数有什么用?
延伸,为什么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 这样是不合理的。
组件
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
短小精悍的中间件
const INCREMENT_MONEY = 'INCREMENT_MONEY'
const mapDispatchToProps = (dispatch)=>({
getMoney:()=>{
setTimeout(()=>{
dispatch({
type:INCREMENT,
})
},500)
}
})
// ...
redux-saga
适合处理比较复杂的异步问题,一些简单场景也提供便利的功能,saga中运行的任务是可取消的,像触发同一个任务的时候可以通过saga的机制总是执行最新的任务。
...
为什么reducers需要纯函数?
因为在遍历store中的key的时候,判断前后状态是通过浅比较。
mobx
通过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>
);
}
}
Why do we need middleware for async flow in Redux?
. 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