Learning Notes - React Hooks
Basic chapter
Reason to Hooks
React的本质就是从Model到View的映射。这里的Model就是Component的props和state。
当Model的数据变化时,React不管它是怎么变化的,只关心它变化之后和之前的区别。这也就是所谓的声明式declarative,而这通过React的diff函数来实现。
所以UI的展现更像是一个函数的执行。Model是输入参数,View是函数,执行结果就是Dom的改变。而React只要保证通过最优的办法执行变化的过程就行了。
Class作为React Component不合适的两点:
- React Component之间很少使用继承.
- React是由state驱动的,并不需要调用外部生成的class的instance的method。
Function作为React Component的局限:
- Function无法提供内部状态,必须是纯函数
- Function也无法提供完整的lifecycle
所以React的中的Hooks就是把target钩到某个可能会变化的data source或者event source中,当被钩到的data或者event变化的时候,这个target会被重新执行,产生新的结果。
Hooks中被钩的对象不仅仅可以是数据,也可以是另一个Hook执行的结果,这样可以带来逻辑的复用。
Hooks是在High order Component的使用背景下被创造出来的,所以Hook解决了HOC留下的wrapper hell和code难以理解的问题
Hooks basic usage
useState
-- 使用useState保存的值的原则是,不要使用需要计算得到的值useEffect
-- 应该用来执行并不影响当前结果的代码,是不影响当前渲染出来的UI的- Deps使用reference来比较值是否有变化,所以数组和object要小心
- NB: useEffect是在render执行之后调用的
useCallback
-- 这个hook的使用目的是,在需要把函数作为值来传递到UI的时候,为了避免多余的render,而保证在某些条件传递的函数本身是不变的useMemo
-- useMemo其实可以理解为useEffect和useState的结合,即在deps变化的时候来执行useEffect的函数来计算值的变化,同时将值通过useState来赋予stateuseRef
- 在多次渲染之间共享数据
- 存某个 DOM 节点的引用
useContext
-- 定义全局状态
useEffect基本上等价于componentDidMount, componentDidUpdate 和componentWillUnmount。但是并不完全等价。区别在于: useEffect的callback函数只有在deps变化的时候才会被调用,而componentDidUpdate则一定会被调用 useEffect里callback函数的返回函数(用来做清理工作),是在依赖项变化或者组件销毁前被调用
如果需要有一个constructor的功能,可以使用以下代码:
1// 创建一个自定义 Hook 用于执行一次性代码
2function useSingleton(callback) {
3 // 用一个 called ref 标记 callback 是否执行过
4 const called = useRef(false);
5 // 如果已经执行过,则直接返回
6 if (called.current) return;
7 // 第一次调用时直接执行
8 callBack();
9 // 设置标记为已执行过
10 called.current = true;
11}
Hook可以实现大部分的lifecycle的功能,但是对于 getSnapshotBeforeUpdate, componentDidCatch, getDerivedStateFromError,这些周期还是只能使用class来实现
Practice
Data consistence
在保证 State 完整性的同时,也要保证它的最小化。 某些数据如果能从已有的 State 中计算得到,那么我们就应该始终在用的时候去计算,而不要把计算的结果存到某个 State 中。
避免中间状态,确保唯一数据源
在任何时候想要定义新状态的时候,都要问自己一下:这个状态有必要吗?是否能通过计算得到?是否只是一个中间状态?
Render props模式
通过把render函数传递给某个组件,让这个render函数来决定渲染的效果,从而实现组件的复用
Self defined event
Synthetic Event
当我们绑定一个时间到节点上的时候,因为virtual dom的存在,react会把时间绑定到APP根节点上,React 17之前是在document上,17以后是在react的根节点上 一是因为virtual dom在render的时候,可能节点还没有render到页面上,所以无法绑定 二是可以屏蔽底层细节,避免浏览器兼容性问题
所以react component自定义的事件本质上是回调函数
Organize project structure via business
为了降低项目的复杂度,通过业务特征和逻辑来组织项目结构,这样可以让各个feature能相对独立,便于管理和维护
为了实现松耦合,可以针对dynamic的部分单独设计组件,并传递动态的参数以达到动态内容的修改不影响其他部分
Form
React是状态驱动,Form是事件驱动 React的onChange函数会在用户任何输入的时候都调用函数,但是html的原生onchange函数则只会在输入框失去focus的时候触发
Controlled vs uncontrolled
对于uncontrolled component,并不会传递value给component,而是通过获取这个component的值来得到其状态,例如useRef。好处在于,其值的变化并不会触发render。坏处则是无法检测值的变化
而对于controlled component,则接受value as props,同时一个callback函数来update这个值
使用Controlled component来维护表单主要核心三个部分:
- 字段的名称
- 绑定value
- 处理onChange事件
所以Hook对于Form的贡献在于,可以把Form里面的value都放到hook里面,并且通过useState来提供处理的函数。例如:
1import { useState, useCallback } from "react";
2
3const useForm = (initialValues = {}) => {
4 // 设置整个 form 的状态:values
5 const [values, setValues] = useState(initialValues);
6
7 // 提供一个方法用于设置 form 上的某个字段的值
8 const setFieldValue = useCallback((name, value) => {
9 setValues((values) => ({
10 ...values,
11 [name]: value,
12 }));
13 }, []);
14
15 // 返回整个 form 的值以及设置值的方法
16 return { values, setFieldValue };
17};