We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
参考文章:
// useState 用法 const [mystate, setMystate] = useState(initialState)
类组件每次重新渲染,都会调用 render 方法以及生命周期函数。同理,在函数组件中,每次重新渲染都会调用函数组件(本身就是构造 UI 的 render 方法),所以定义在函数组件内的方法都会被重新定义并执行,按理来说 state 状态会被覆盖重置,但 React Hooks 能在重复渲染时保留上一个 state 状态,并作为下一次改变的初始值。
(函数组件外定义的方法不会重新定义,因此我们可以利用闭包特性保留一些值,当然也可用后续提及的 useMemo, useCallback 等 Hooks)
setState()
useState 只能用于 React 函数组件或自定义 Hook 的最外层,但它返回的修改 state 的方法可以用于其他位置或多层嵌套中。
useState 返回的用于更新 state 状态的方法,在更新机制上与 setState 类似,setState 的更新机制可参考我的另一篇文章:React - setState 学习笔记。
setState
useState 返回的更新方法,也是异步的。它会等待同步代码执行完毕后,再更新 state,然后触发 render 和生命周期函数,重新渲染组件并执行定义的副作用。
Object.is
这主要与 React Hooks 的闭包特性有关,可参考 超性感的React Hooks(二)再谈闭包。useState 会将 state 保存,形成一个闭包,当接受的值与保存的 state 经过 Object.is 比较相等时,useState 会直接使用原有的 state。
// useState 简单实现 let state = null; export const useState = (value: number) => { // 第一次调用时没有初始值,因此使用传入的初始值赋值 state = state || value; function dispatch(newValue) { if (!Object.is(state, newValue)) { state = newValue; // 假设此方法能触发页面渲染 render(); } } return [state, dispatch]; }
与 setState 不同点在于,setState 会将接收的对象合并到实例 state 对象上,并覆盖同名属性。
如果新的 state 需要通过使用先前的 state 计算得出,那么可以将回调函数当做参数传递给 setState。该回调函数将接收先前的 state,并返回一个更新后的值。
let [mystate, setMystate] = useState(false); ... setMystate((prev) => (prev + 1));
与 setState 函数式更新区别在于,它不接受当前 props 作为参数,因为在函数组件内部的嵌套函数本身就可以通过作用域获取 props,不需要将其作为形参传入回调函数。 推荐使用函数式更新,详细原因见文章:函数式 setState
即仅作用于组件创建,不作用于组件重新渲染。
function getInitState() { // do something return xxx } // getInitState 在其所在组件首次被创建中调用。 let [counter,setCounter] = useState(getInitState);
每一个hook都是相互独立的,这就意味着不同组件调用同一个hook也能保证各自状态的独立性。
// 组件 A let [a, setA] = useState(false) // 组件 B let [b, setB] = useState(123)
如上例,不同组件内都调用了 useState 这一个 Hook,但由于每个 Hook 都是独立的,因此每个 Hook 调用都返回独立的结果,保证了不同组件调用同一个hook也能保证各自状态的独立性。
React Hooks 实现了独立性,但是 React 是怎么知道组件 A 调用的 useState 对应的是数组 [a, setA] 呢? 这就涉及了 React Hooks 定义的顺序性问题。 实际上,react 是根据 Hooks 出现的顺序来定的,以 useState 为例:
//第一次渲染 useState(42); //将age初始化为42 useState('banana'); //将fruit初始化为banana useState([{ text: 'Learn Hooks' }]); //... //第二次渲染 useState(42); //读取状态变量age的值(这时候传的参数42直接被忽略) // useState('banana'); useState([{ text: 'Learn Hooks' }]); //读取到的却是状态变量fruit的值,导致报错
在组件初始化(创建)时,React 会根据 useState 书写顺序存储对应的值,并构成一个链表结构,后续组件重新渲染时,会按照链表顺序遍历移动指针,并调用相应的 Hook。
React Hooks 对顺序性的要求,也约束了开发者书写 Hooks 的行为。我们只能将 Hooks 写在函数的最外层,不能写在 if ... else ... 或循环等语句中,确保 Hooks 的执行顺序与存储到链表结构中的顺序一致。
if ... else ...
The text was updated successfully, but these errors were encountered:
No branches or pull requests
React - Hooks (useState)
参考文章:
useState
setState()
类似,你可以在事件处理函数中或其他一些地方调用这个函数来更新 state。它与setState()
区别在于:它不会把新的 state 和旧的 state 进行合并,而是直接替换。state 更新机制
useState 返回的用于更新 state 状态的方法,在更新机制上与
setState
类似,setState
的更新机制可参考我的另一篇文章:React - setState 学习笔记。Hook state 更新特点
Object.is
来比较新/旧 state 是否相等。函数式更新
如果新的 state 需要通过使用先前的 state 计算得出,那么可以将回调函数当做参数传递给 setState。该回调函数将接收先前的 state,并返回一个更新后的值。
初始化 state 惰性求值
Hooks 独立性 & 顺序性
独立性
每一个hook都是相互独立的,这就意味着不同组件调用同一个hook也能保证各自状态的独立性。
如上例,不同组件内都调用了 useState 这一个 Hook,但由于每个 Hook 都是独立的,因此每个 Hook 调用都返回独立的结果,保证了不同组件调用同一个hook也能保证各自状态的独立性。
顺序性
React Hooks 实现了独立性,但是 React 是怎么知道组件 A 调用的 useState 对应的是数组 [a, setA] 呢?
这就涉及了 React Hooks 定义的顺序性问题。
实际上,react 是根据 Hooks 出现的顺序来定的,以 useState 为例:
在组件初始化(创建)时,React 会根据 useState 书写顺序存储对应的值,并构成一个链表结构,后续组件重新渲染时,会按照链表顺序遍历移动指针,并调用相应的 Hook。
The text was updated successfully, but these errors were encountered: