重新解读React.Component
一篇笔记, 参考官方教程并且加上了很多批注
React.Component 是一个抽象基类, 基本结构:
class Greeting extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
最小配置就是一个render()
函数
当一个 component 加载并且加入 DOM 的时候执行
These methods are called when an instance of a component is being created and inserted into the DOM:
当一个 component 重新渲染的时候执行
An update can be caused by changes to props or state. These methods are called when a component is being re-rendered:
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
删除时执行
This method is called when a component is being removed from the DOM:
当 render 的时候报错
This method is called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.
这个函数可以返回以下内容:
- React elements. Typically created via JSX. An element can either be a representation of a native DOM component (
<div />
), or a user-defined composite component (<MyComponent />
). - String and numbers. These are rendered as text nodes in the DOM.
- Portals. Created with
ReactDOM.createPortal
. null
. Renders nothing.- Booleans. Render nothing. (Mostly exists to support
return test && <Child />
pattern, wheretest
is boolean.)
用于返回一个 DOM 时并且用上某些条件的情况
- When returning null or false,
ReactDOM.findDOMNode(this)
will return null. render()
will not be invoked ifshouldComponentUpdate()
returns false.
The render()
function should be pure, meaning that it does not modify component state, it returns the same result each time it』s invoked, and it does not directly interact with the browser.
render()
一般不要改变 state 里面的内容, 保证这个函数就做单一的渲染这个事情
If you need to interact with the browser, perform your work in componentDidMount()
or the other lifecycle methods instead. Keeping render()
pure makes components easier to think about.
render()
这个函数里面也可以返回一个 DOM 数组:
render() { return [ <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; }
React V16.2 之后也可以用这个方法
render() { return ( <React.Fragment> <li>First item</li> <li>Second item</li> <li>Third item</li> </React.Fragment> ); }
区别就在于不需要提供
key
了
mount
状态之前执行这个函数- 可以通过
super(props)
调用父类的方法 - 并且如果不调用
super(props)
的话,this.props
就会变成undefined - 应该在这个函数里初始化
this.state
- 并且不要在这个函数里使用
setState()
- 当然如果我需要绑定函数, 也没有状态变化的话, 就完全不需接入这个接口了
mount
发生的时候立刻执行- 在
render()
之前执行 - 但是和
render()
不一样,setState()
之后, 不会重复执行一次
mount
状态之后执行这个函数- 对于 DOM 的一系列 init 可以放在这个地方
- 进行各类网络请求的最佳地点, 比如 AJAX 获取数据之类的
- 注册
subscription
的最佳地点, 当然不要忘记在componentWillUnmount()
注销subscription
- 关于 subscription
- 就是类似于 GQL 之类的玩意
setState()
之后, 重复执行一次- 上面这个用法的时候一定要注意性能问题
- 无论新的和旧的 prop 是否相等都会执行这个函数
- 另外需要注意的是
mount
状态的时候并不会执行这个函数, 也就是说, 初始化的时候并不会执行这个函数
这个很容易理解了
有一些情况就是不通过
state
而通过props
来刷新的情况, 就可以在这个函数里面判断新的和旧的 prop 是否相等, 并根据判断结果刷新state
- 在新的 prop 或者 state 接收到的时候, 并且在刷新之前执行
- 默认情况下返回
true
, 这个函数会导致render()
刷新 - 另外就算是返回
false
, 也无法防止子模块的刷新 - Currently, if
shouldComponentUpdate()
returnsfalse
, thencomponentWillUpdate()
,render()
, andcomponentDidUpdate()
- 在新的
props
和state
获取到之前执行 - 因此可以在这儿执行一些 update 的准备活动
- 当然不要在这里面修改
state
和props
- 如果非要修改的话, 最好使用
componentWillReceiveProps()
- 这个函数的是否执行与
shouldComponentUpdate()
的返回值相关
- 这个就是在更新时候执行
- 对于一些 DOM 的处理可以放在这个地方
- 另外可以在这个地方判断一下
props
是否改变, 并根据这个结果决定是否发送 http 请求 - 这个函数的是否执行与
shouldComponentUpdate()
的返回值相关
- 当元素销毁的时候执行, 因此适合执行一些善后工作
- 比如计时器的关闭, 网络请求关闭, subscriptions 的清理等等
(待补充)
- 修改界面的主要方式
- 最好将这个函数看成一个请求, 因为实现更新可能会有一定的延迟, 也有可能将一系列的更新批次完成
- 正因为不会立刻执行, 对于
state
的读取就必须要小心, 推荐使用componentDidUpdate()
- 除非
shouldComponentUpdate()
返回了false
, 否则这个函数的执行一定会重新渲染界面 - 因此通过一定条件判断是否使用这个函数, 可以避免一些不必要的重新渲染
- 第一个参数是个 updater function
- 第一个参数也可以直接放一个 Obj, 会被自动 merge 到
state
中 - 第二个参数是一个 callback, 当
state
修改之后执行
this.setState((prevState, props) => { return {counter: prevState.counter + props.step}; });
this.setState({quantity: 2})
这个函数的执行是异步的, 因此如果有这样的执行:
Object.assign( previousState, {quantity: state.quantity + 1}, {quantity: state.quantity + 1}, …… )
最后可能仅仅加了 1
因此如果要改变的状态和历史状态有关, 那么最好使用 updater 函数
this.setState((prevState) => { return {quantity: prevState.quantity + 1}; });
- 对于当前模块强行调用
render()
, 并且忽略shouldComponentUpdate()
的限制 - 同时也会调用所有子模块的
render()
, 但是会根据它们的生命周期判断shouldComponentUpdate()
的值 - 当然不推荐使用这个方法, 尽可能仅仅通过
props
以及state
进行重新渲染
这个是直接给一个模块提供默认的prop
class CustomButton extends React.Component { // …… } CustomButton.defaultProps = { color: 'blue' }; …… render() { return <CustomButton /> ; // props.color will be set to blue }
但是注意, 不管给任何值, 只要给了值, 就一定会覆盖掉默认值
render() { return <CustomButton color={null} /> ; // props.color will remain null }
这个其实是 debug 的时候方便查看用的
没什么好说的了
this.props.children
这个比较特别,这个包含了所有子标签的 JSX
- 永远不要直接修改这个词一定要通过
setState()
来进行修改
关于本文
文章标题 | 重新解读React.Component |
发布日期 | 2018-02-28 |
文章分类 | Tech |
相关标签 | #React |
留言板
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER