|
1 | | -# ReactHooksTraining |
| 1 | +Hooks 新人培训演讲大纲 |
| 2 | + |
| 3 | +### React Logo 与 Hooks |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +React 的 logo 是一个原子图案, 原子组成了物质。类似的, React 就如原子般构成了页面的表现; 而 Hooks 就如夸克, 其更接近 React 本质的样子, 但是直到 4 年后的今天才被真正设计出来。 —— Dan in React Conf(2018) |
| 8 | + |
| 9 | +### why Hooks? |
| 10 | + |
| 11 | +一: `多个组件间逻辑复用`: 在 Class 中使用 React 不能将带有 state 的逻辑给单独抽离成 function, 其只能通过嵌套组件的方式来解决多个组件间逻辑复用的问题, 基于嵌套组件的思想存在 [HOC](https://github.com/MuYunyun/blog/blob/master/React/从0到1实现React/8.HOC探索.md) 与 `render props` 两种设计模式。但是这两种设计模式是否存在缺陷呢? |
| 12 | + |
| 13 | +* 嵌套地狱, 当嵌套层级过多后, 数据源的追溯会变得十分困难, 导致定位 bug 不容易; (hoc、render props) |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +* 性能, 需要额外的组件实例存在额外的开销; (hoc、render props) |
| 18 | +* 命名重复性, 在一个组件中同时使用多个 hoc, 不排除这些 hoc 里的方法存在命名冲突的问题; (hoc) |
| 19 | + |
| 20 | +二: `单个组件中的逻辑复用`: Class 中的生命周期 `componentDidMount`、`componentDidUpdate` 甚至 `componentWillUnMount` 中的大多数逻辑基本是类似的, 必须拆散在不同生命周期中维护相同的逻辑对使用者是不友好的, 这样也造成了组件的代码量增加。 |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | +三: Class 的其它一些问题: 在 React 使用 Class 需要书写大量样板, 用户通常会对 Class 中 Constructor 的 bind 以及 this 的使用感到困惑; 当结合 class 与 TypeScript 一起使用时, 需要对 defaultValue 做额外声明处理; 此外 React Team 表示 Class 在机器编译优化方面也不是很理想。 |
| 27 | + |
| 28 | +### React Hooks 使用中的问题 |
| 29 | + |
| 30 | +#### 闭包陷阱 |
| 31 | + |
| 32 | +* demo1: 闭包陷阱1。 [Demo 地址](https://codesandbox.io/s/22y21468r) |
| 33 | + |
| 34 | +1. Hooks/class demo 对比演示; |
| 35 | +2. Hooks/class 互相切换为对方的形态; |
| 36 | + |
| 37 | +结论: 问题不在于是使用 Hooks 还是 class, 本质是受到闭包的影响。 |
| 38 | + |
| 39 | +* demo2: 闭包陷阱2 |
| 40 | + |
| 41 | +由 Class 转换过来的用户习惯 `setCount(count + 1))` 的方式。但在 Hooks 中这样子使用会产生闭包问题导致 `count` 不会增加。 |
| 42 | + |
| 43 | +```js |
| 44 | +function Demo() { |
| 45 | + const [count, setCount] = React.useState(0) |
| 46 | + useEffect(() => { |
| 47 | + const id = setInterval(() => { |
| 48 | + setCount(count + 1) |
| 49 | + }, 2000) |
| 50 | + |
| 51 | + return () => { |
| 52 | + clearInterval(id) |
| 53 | + } |
| 54 | + }, []) |
| 55 | + return ( |
| 56 | + <div>Count: {count}</div> |
| 57 | + ) |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +提供 3 种解法。用户说还是想用 `setCount(count + 1)` 的形式怎么办 |
| 62 | + |
| 63 | +引出为此提供 `useInterval` 钩子, 顺利过渡到 `beast-hooks` |
| 64 | + |
| 65 | +```js |
| 66 | +function useInterval(callback, delay: number) { |
| 67 | + const cbRef = useRef({}) |
| 68 | + useEffect(() => { |
| 69 | + cbRef.current = callback |
| 70 | + }, [callback]) |
| 71 | + useEffect(() => { |
| 72 | + setInterval(() => { |
| 73 | + cbRef.current() |
| 74 | + }, delay) |
| 75 | + }, [delay]) |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +用法: |
| 80 | + |
| 81 | +```js |
| 82 | +function Demo() { |
| 83 | + const [count, setCount] = React.useState(0) |
| 84 | + |
| 85 | + useInterval(() => { |
| 86 | + setCount(count + 1) |
| 87 | + }, 2000) |
| 88 | + |
| 89 | + return (<div>Count: {count}</div>) |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +### React Hooks 内部探究 |
| 94 | + |
| 95 | +以 `useState` 和 `useReducer` 为例 |
| 96 | + |
| 97 | +#### 使用 useState 实现 useReducer |
| 98 | + |
| 99 | +```js |
| 100 | +import * as React from 'react' |
| 101 | +const { useState, useRef, useCallback } = React |
| 102 | + |
| 103 | +function useReducer(reducer, initialState) { |
| 104 | + const [state, setState] = useState(initialState) |
| 105 | + const reducerRef = useRef(reducer) |
| 106 | + const stateRef = useRef(state) |
| 107 | + |
| 108 | + const dispatch = useCallback((action) => { |
| 109 | + setState(reducerRef.current(stateRef.current, action)) |
| 110 | + }, []) |
| 111 | + |
| 112 | + useEffect(() => { |
| 113 | + reducerRef.current = reducer |
| 114 | + }, [reducer]) |
| 115 | + |
| 116 | + useEffect(() => { |
| 117 | + stateRef.current = state |
| 118 | + }, [state]) |
| 119 | + |
| 120 | + return [state, dispatch] |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +#### 使用 useReducer 实现 useState |
| 125 | + |
| 126 | +```js |
| 127 | +import * as React from 'react' |
| 128 | +const { useReducer, useCallback } = React |
| 129 | + |
| 130 | +function useState(initialState) { |
| 131 | + const [state, dispatch] = useReducer((state, action) => { |
| 132 | + return action |
| 133 | + }, initialState) |
| 134 | + |
| 135 | + const setState = useCallback( |
| 136 | + (newState) => dispatch(newState), [] |
| 137 | + ) |
| 138 | + |
| 139 | + return [state, setState] |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +### 相关链接 |
| 144 | + |
| 145 | +* [React Hooks 深入系列](https://github.com/MuYunyun/blog/blob/master/React/React_Hooks深入系列.md) |
| 146 | +* [React Hooks 设计模式](https://github.com/MuYunyun/blog/blob/master/React/React_Hooks设计模式.md) |
0 commit comments