Hooks 只能用于 React 函数式组件
函数式组件严格遵循 UI = render(data) 的模式
函数式组件
使用函数式组件时需要将组件申明为 React.FC类型,也就是Function Component的意思,props也需要申明各个参数的类型,并通过泛型传递给React.FC. 还支持children的传入
1 | import React from 'react' |
useState
const [state, setState] = useState(initialValue);
state 就是一个状态变量,setState 是一个用于修改状态的 Setter 函数,而 initialValue 则是状态的初始值。
优化了this.state 和 this.setState ,不用频繁使用this., 参数可以为基本类型,也可以为对象类型,为对象类型的时候,setXXX并不会像this.setState一样合并旧的状态,而是完全替代了旧的状态,如果要实现合并的话,需要使用扩展运算符, 如下面第二句
1 | const [cout, setCount] = useState<number>(0) |
useEffect
useEffect(effectFn, deps)
effectFn 是一个执行某些可能具有副作用的 Effect 函数(例如数据获取、设置/销毁定时器等),它可以返回一个清理函数(Cleanup),例如大家所熟悉的 setInterval 和 clearInterval
可以将useEffect看作 componentDidMount, componentDidUpdate 和 componentWillUnmount三个函数的组合
1 | useEffect(() => { |
- 每个 Effect 必然在渲染之后执行,因此不会阻塞渲染,提高了性能
- 在运行每个 Effect 之前,运行前一次渲染的 Effect Cleanup 函数(如果有的话)
- 当组件销毁时,运行最后一次 Effect 的 Cleanup 函数
- 将 Effect 推迟到渲染完成之后执行是出于性能的考虑,如果你想在渲染之前执行某些逻辑(不惜牺牲渲染性能),那么可使用
useLayoutEffect
[10] 钩子,使用方法与 useEffect 完全一致,只是执行的时机不同。 - 在最极端的情况下,我们可以指定 deps 为空数组 [] ,这样可以确保 Effect 只会在组件初次渲染后执行
- 强烈建议你不要把 Effect 写成一个 async 函数,useEffect 约定 Effect 函数要么没有返回值,要么返回一个 Cleanup 函数。而这里 async 函数会隐式地返回一个 Promise,直接违反了这一约定,会造成不可预测的结果。
多个 State 和 Effect情况下
多个 State
- 在初次渲染时,我们通过 useState 定义了多个状态;
- 每调用一次 useState ,都会在组件之外生成一条 Hook 记录,同时包括状态值(用 useState 给3. 定的初始值初始化)和修改状态的 Setter 函数;
- 多次调用 useState 生成的 Hook 记录形成了一条链表;
- 触发 onClick 回调函数,调用 setS2 函数修改 s2 的状态,不仅修改了 Hook 记录中的状态值,还即将触发重渲染
多个Effect
- useState 和 useEffect 在每次调用时都被添加到 Hook 链表中;
- useEffect 还会额外地在一个队列中添加一个等待执行的 Effect 函数;
- 在渲染完成后,依次调用 Effect 队列中的每一个 Effect 函数。
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
其中第一个参数是一个函数,这个函数返回值的返回值(也就是上面 computeExpensiveValue 的结果)将返回给 memoizedValue ,因此以下两个钩子的使用是完全等价的:
useCallback(fn, deps);
useMemo(() => fn, deps);
useMemo 则是一个” 全能型选手 “,能够同时胜任引用相等和节约计算的任务。实际上,useMemo 的功能是 useCallback 的超集。与 useCallback 只能缓存函数相比,useMemo 可以缓存任何类型的值(当然也包括函数)。
useCallback
const memoizedCallback = useCallback(callback, deps);
第一个参数 callback 就是需要记忆的函数,第二个参数就是大家熟悉的 deps 参数,同样也是一个依赖数组(有时候也被称为输入 inputs)。在 Memoization 的上下文中,这个 deps 的作用相当于缓存中的键(Key),如果键没有改变,那么就直接返回缓存中的函数,并且确保是引用相同的函数。
在大多数情况下,我们都是传入空数组 [] 作为 deps 参数,这样 useCallback 返回的就始终是同一个函数,永远不会更新。
useCallback 主要是为了解决函数的” 引用相等 “问题
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
第一个参数 reducer 显然是必须的,它的形式跟 Redux 中的 Reducer 函数完全一致,即 (state, action) => newState。
第二个参数 initialArg 就是状态的初始值。
第三个参数 init 是一个可选的用于懒初始化(Lazy Initialization)的函数,这个函数返回初始化后的状态。
· 使用前提
- 需要维护的状态本身比较复杂,多个状态之间相互依赖
- 修改状态的过程比较复杂
useContext
通过 useContext ,我们就可以轻松地让所有组件都能获取到 dispatch 函数
// 在某个文件中定义 MyContext
const MyContext = React.createContext(‘hello’);
// 在函数式组件中获取 Context
function Component() {
const value = useContext(MyContext);
// ...
}
Redux基本思想
![image-20200508141650250](/Users/wangjuan/Library/Application Support/typora-user-images/image-20200508141650250.png)