React 小黑板 - 进阶

131 阅读4分钟

Context

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。 我的想法是能不用就不用,项目复杂调试起来费劲。

JSX高级

  1. 可以使用点语法来引用一个 React 组件
  2. 用户定义的组件必须以大写字母开头, 为了与html中的标签区别
  3. 不能将通用表达式作为 React 元素类型
  4. props可以是表达式
  5. props的默认值是boolean型的true
  6. falsenullundefined, and true 是合法的子元素,但它们并不会被渲染。一种例外是尽管数字0弱比较时与false相等,但它会被渲染

性能优化

  • 循环使用 key
  • 修改 css 模拟 v-show
  • 使用 Fragment 减少层级
  • 在构造函数 bind this
  • 使用开发工具对组件进行分析
  • 虚拟化长列表 react-window 和 react-virtualized
  • shouldComponentUpdate,使用该生命周期钩子控制非必要的组件更新。
shouldComponentUpdate(nextProps, nextState) {
  return true;
}

当然大多时候使用React.PureComponent来代替以上方法,但是它仅适合浅比较,如果props或则state的属性的结构变得复杂就不适合了,比如对象或则数组

Diffing算法

新render的虚拟DOM数与旧的虚拟DOM数进行对比,仅更新不同的部分 两个策略:

  1. 判断元素类型,相同继续;不同,直接新生成DOM节点
  2. 如果存在多个同类型的子元素,引入key来进行判断,从而降低开销

Hooks

它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。注意仅可以在函数声明组件中使用,在class声明组件中不可以使用

解决的问题

组件间复用状态和逻辑以及复杂逻辑的更细粒度的拆分,React 需要为共享状态逻辑提供更好的原生途径

使用限制

  1. 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  2. 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。当然还可以在自定义Hook中使用

State Hook

状态钩子 声明一个叫num的状态

const [num, setNum] = useState(0)
// 0为初始值

不像 class 中的 this.setState,更新 state 变量总是*替换*它而不是合并它

Effect Hook

副作用钩子 有些副作用可能需要清除,所以需要返回一个函数:

// 相当于 componentDidMount, componentDidUpdate and componentWillUnmount:  
useEffect(() => {    
// todo something 
    return ()=>{
        // todo clean up
    } 
});

其他的 effect 可能不必清除,所以不需要返回

// 相当于 componentDidMount and componentDidUpdate:  
useEffect(() => {    
// todo something 
    return ()=>{
        // todo clean up
    } 
});

注意点

  1. effect 的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件的时候执行一次
  2. 通过跳过 Effect 进行性能优化, useEffect的第二个参数来解决这个问题,近参数中指定的状态变化才执行副作用 不使用useEffects是如何实现的? 使用生命周期钩子componentDidUpdate(preProps, preState){//判断状态或则属性改不改变,来确认某一段逻辑是否执行}

自定义Hook

有时候我们会想要在组件之间重用一些状态逻辑。目前为止,有两种主流方案来解决这个问题:高阶组件和 render props。自定义 Hook 可以让你在不增加组件的情况下达到同样的目的。 自定义组件必须以use开头,约定

FAQ

  1. 多个hook一起使用,如何确定状态和作用与hook之间的关系? 根据hook的调用顺序。这也是为什么要求hook不能写在判断和循环语句中
// ------------
// 首次渲染
// ------------
useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题

// -------------
// 二次渲染
// -------------
useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
useEffect(persistForm)     // 2. 替换保存 form 的 effect
useState('Poppins')        // 3. 读取变量名为 surname 的 state(参数被忽略)
useEffect(updateTitle)     // 4. 替换更新标题的 effect

// ...

注意

事件处理

  1. function,bind(this) 传参使用data-attr,例如date-id={id}, 获取通过event.target.dataset.id
  2. render中使用箭头函数, 传参使用(id)=>{func(id)}
  3. render中使用bind,传参使用bind(this, id)
  4. class 属性 fun = ()=>{} 以上为class声明组件,以下为函数组件
  5. function fun(){} 传参通过return 中使用箭头函数 (id)=>{fun(id)}
  6. const fun = ()=>{} 传参通过return 中使用箭头函数 (id)=>{fun(id)}