React State与生命周期
一、React State介绍
React将组件看成是一个状态机(State Machines),通过其内部定义的状态State与生命周期Lifecycle实现与用户的交互,维持组建的不同状态。
React为什么定义State概念?
只需要通过更新React组件的状态State,就可以实现重新渲染用户界面的操作,这样就不需要操作DOM了。
state的创建:
class MyComponent extends React.Component {
constructor(props) { //构造函数
super(props); //必须是构造函数的第一句
this.state = { // 状态机
value:'Hello'
}
}
}
什么时候使用State?
由于React对props的严格保护机制,一旦给定值,在组件中是不允许改变的,但是很多应用场合中,组件的内容需要根据数据的刷新而刷新,这个时候就需要用到React提供的State,即状态机。
二、React组件的生命周期
每个组件都包含“生命周期法”,可以通过重写这些方法,实现在运行过程中特定的阶段执行这些方法。
(1)挂载
当组件实例被创建并插入DOM中时,其生命周期调用顺序如下:
- constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
构造函数:constructor(props): 在React组件挂载之前,会调用它的构造函数。
构造函数的使用:
- 通过给this.state赋值对象来初始化内部state
- 为事件处理函数绑定实例
注:如果不初始化state或不进行方法绑定,则不需要为React组件实现构造函数。在为React.Component子类实现构造函数时,应在其他语句前调用super(props),否则this.props在构造函数中可能会出现未定义的bug。
在constructor()函数中不要调用setState()方法。如果组件需要使用内部state,请直接在构造函数中为this.state赋值初始化state。
constructor(props){
super(props);
//不要在这里调用this.setState()
this.state={counter:0};
this.handleClick=this.handleClick.bind(this);
}
render(): 是class组件中唯一必须实现的方法。
当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:
- React 元素。 通常通过 JSX 创建。例如,< div /> 会被 React 渲染为 DOM 节点,< MyComponent />会被 React 渲染为自定义组件,无论是 < div /> 还是 < MyComponent /> 均为 React 元素。
- 数组或fragments。 使得 render 方法可以返回多个元素。
- Portals。 可以渲染子节点到不同的 DOM 子树中。
- 字符串或数值类型。 它们在 DOM 中会被渲染为文本节点。
- 布尔类型或 null。 什么都不渲染。
componentDidMount(): 在组件挂载后(插入DOM树中)立即调用。
函数内部适合的事件:依赖于DOM节点的初始化,通过网络请求数据,添加订阅。
注:如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅。
可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 constructor() 中初始化 state。如果你的渲染依赖于DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理
(2)更新
当组件的props或state发生变化时会触发更新,组建更新的生命周期调用顺序如下:
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- reander()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot): 会在更新后会被立即调用,首次渲染不会执行此方法。
当组件更新后,可以在此处对 DOM 进行操作。
componentDidUpdate(prevProps){
//典型用法,不要忘记比较props:
if(this.props.userID!==prevProps.userID){
this.fetchData(this.props.userID);
}
}
也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。
(3)卸载
当组件从DOM中移除时会调用如下方法:
componentWillUnmount():
该方法会在组件卸载及销毁之前直接使用,在此方法中执行必要的清理操作,例如清除timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
注:componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。