1. react.Component
React 的所有组件都继承自顶层类 React.Component。它的定义非常简洁,只是初始化了
React.Component 方法,声明了 props、context、refs 等,并在原型上定义了 setState 和
forceUpdate 方法.
2. 无状态函数
示例代码如下:
function Button({ color = 'blue', text = 'Confirm' }) { return ( <button className={`btn btn-${color}`}> <em>{text}</em> </button> ); }
无状态组件只传入 props 和 context 两个参数;也就是说,它不存在 state,也没有生命周
期方法,组件本身即上面两种 React 组件构建方法中的 render 方法。不过,像 propTypes 和
defaultProps 还是可以通过向方法设置静态属性来实现的。
在适合的情况下,我们都应该且必须使用无状态组件。无状态组件不像上述两种方法在调用
时会创建新实例,它创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部
优化。
3.props与state
state 与 props 是 React 组件中最重要的概念。如果顶层组件初始化 props,那么 React 会向下
遍历整棵组件树,重新尝试渲染所有相关的子组件。而 state 只关心每个组件自己内部的状态,
这些状态只能在组件内改变。把组件看成一个函数,那么它接受了 props 作为参数,内部由 state
作为函数的内部参数,返回一个 Virtual DOM 的实现。
4. 生命周期
componentWillMount 方法会在 render 方法之前执行,而componentDIdMount方法会在render之后执行,分别代表了渲染前后的时刻。
如果我们在 componentWillMount 中执行 setState 方法,会发生什么呢?组件会更新 state,
但组件只渲染一次。因此,这是无意义的执行,初始化时的 state 都可以放在 this.state。
如果我们在 componentDidMount 中执行 setState 方法,又会发生什么呢?组件当然会再次更
新,不过在初始化过程就渲染了两次组件,这并不是一件好事。但实际情况是,有一些场景不得
不需要 setState,比如计算组件的位置或宽高时,就不得不让组件先渲染,更新必要的信息后,
再次渲染。
shouldComponentUpdate 是一个特别的方法,它接收需要更新的 props 和 state,让开发者增加
必要的条件判断,让其在需要时更新,不需要时不更新。因此,当方法返回 false 的时候,组件
不再向下执行生命周期方法。
5. 计算DOM的尺寸
React 中使用 DOM 最多的还是计算 DOM 的尺寸(即位置信息)。我们可以提供像 width 或
height 这样的工具函数:
function width(el) { const styles = el.ownerDocument.defaultView.getComputedStyle(el, null); const width = parseFloat(styles.width.indexOf('px') !== -1 ? styles.width : 0); const boxSizing = styles.boxSizing || 'content-box'; if (boxSizing === 'border-box') { return width; } const borderLeftWidth = parseFloat(styles.borderLeftWidth); const borderRightWidth = parseFloat(styles.borderRightWidth); const paddingLeft = parseFloat(styles.paddingLeft); const paddingRight = parseFloat(styles.paddingRight); return width - borderRightWidth - borderLeftWidth - paddingLeft - paddingRight; }
6. react中绑定原声事件
componentDidMount 会在组件已经完成安装并且在浏览器
中存在真实的 DOM 后调用,此时我们就可以完成原生事件的绑定。比如:
import React, { Component } from 'react'; class NativeEventDemo extends Component { componentDidMount() { this.refs.button.addEventListener('click', e => { this.handleClick(e); }); } handleClick(e) { console.log(e); } componentWillUnmount() { this.refs.button.removeEventListener('click'); } render() { return <button ref="button">Test</button>; } }
值得注意的是,在 React 中使用 DOM 原生事件时,一定要在组件卸载时手动移除,否则很
可能出现内存泄漏的问题。而使用合成事件系统时则不需要,因为 React 内部已经帮你妥善地处
理了。
7. 使用原生事件时冒泡的问题
用 reactEvent.nativeEvent.stopPropagation() 来阻止冒泡是不行的。阻止 React 事件冒泡的行为只能用于 React 合成事件系统
中,且没办法阻止原生事件的冒泡。反之,在原生事件中的阻止冒泡行为,却可以阻止 React 合成事件的传播。
消除冒泡例子, 点击二维码外的位置收起二维码
componentDidMount() { document.body.addEventListener('click', e => { if (e.target && e.target.matches('div.code')) { // code是二维码的className return; } this.setState({ active: false, }); }); }
8.