React@16.x(22)HOOK,useState 的原理

打印 上一主题 下一主题

主题 658|帖子 658|积分 1974

1,先容

1,出现时间点:在 React@16.8.0 出现。
2,目标:为了增强函数组件的功能,用于替换类组件(类组件中不能使用 HOOK)。
3,原因:类组件中有一些比力麻烦的问题:this 指向、繁琐的生命周期等问题。
4,特点:本质上就是一个函数,该函数可以挂载(hook)一些功能。
最常用的2个HOOK:


  • useState,作为状态使用。
  • useEffect,作为生命周期使用。
2,useState

一个函数组件中可以有多个状态,这种做法非常有利于横向切分关注点。
2.1,使用

简朴举例:
  1. import React, { useState } from "react";
  2. export default function App() {
  3.     const [n, setN] = useState(0); //使用一个状态,该状态的默认值是0
  4.     return (
  5.         <div>
  6.             <button
  7.                 onClick={() => {
  8.                     setN(n - 1);
  9.                 }}
  10.             >
  11.                 -
  12.             </button>
  13.             <span>{n}</span>
  14.             <button
  15.                 onClick={() => {
  16.                     setN(n + 1);
  17.                 }}
  18.             >
  19.                 +
  20.             </button>
  21.         </div>
  22.     );
  23. }
复制代码
2.2,原理

正常情况下,函数组件重新渲染(重新运行),函数体中的内容不会保存,并且会返回新的内容。那状态是怎样保持的
在之前的渲染流程中提到:React 元素会创建React 节点,ReactDOM 会通过节点来举行渲染
这里做一些补充:
在创建节点的过程中,也会创建并维护一个状态数组,它附着在节点上
第N次调用 useState 时,会检查节点对应的状态数组是否存在下标N


  • 不存在(初次渲染),则使用默认值创建一个状态,并将该状态加入到下标N的位置。
  • 存在(再次渲染),忽略掉默认值,直接取对应下标的状态值。
   另外,正因为 React节点是通过 React 元素创建的,所以React 元素之间相互独立导致每个状态数组 也是独立的,互不影响。
  2.3,留意点

1,全部的 useState 最好写到函数起始位置,便于阅读。
   至少要写到第一次使用该状态之前。
  2,useState严禁出现在代码块中(判断,循环)。
3,useState 返回的函数(数组第2项),引用不变。
   函数组件多次渲染时,该状态函数是同一个,为了节省内存。
  4,使用状态函数修改状态时,若传递的状态值未做修改(使用Object.is() 比力),不会导致重新渲染。这是为了优化效率。
5,强制刷新。如果状态值是一个对象,则可通过传入一个空对象来实现强制渲染。(2个对象引用差别)
  1. export default function App() {
  2.     console.log("App Render");
  3.     const [, forceUpdate] = useState({});
  4.     return (
  5.         <div>
  6.             <button
  7.                 onClick={() => {
  8.                     forceUpdate({});
  9.                 }}
  10.             >
  11.                 强制刷新
  12.             </button>
  13.         </div>
  14.     );
  15. }
复制代码
6,使用状态函数修改状态时,新传入的值会直接替换旧值,而不是归并。
  1. // 使用解构,保留之前的状态
  2. export default function App() {
  3.     const [data, setData] = useState({ x: 1, y: 2 });
  4.     return (
  5.         <div>
  6.             <span>{data.x}</span>
  7.             <span>{data.y}</span>
  8.             <button
  9.                 onClick={() => {
  10.                     setData({
  11.                         ...data,
  12.                         x: data.x + 1,
  13.                     });
  14.                 }}
  15.             >
  16.                 x+1
  17.             </button>
  18.         </div>
  19.     );
  20. }
复制代码
7,如果状态之间没有一定联系,应该分开处理,而不是归并为一个对象。
8,和类组件的状态相似,函数组件中改变状态也大概是异步的(比如DOM变乱),多个状态的修改会集并,以进步效率。
所以,不能信托之前的状态。如果需要用到之前的状态,可以使用函数参数。
   和类组件的 setState 一样,如果参数是函数的话,会将每个状态函数的函数参数放到一个队列中,按序次执行。队列执行完毕后,再更新真正的 state,再执行 render(只执行了1次)。
  举例:每次点击按钮,n+2,同时只打印一次 App render。
  1. import React, { useState } from "react";
  2. export default function App() {
  3.     console.log("App render");
  4.     const [n, setN] = useState(0);
  5.     return (
  6.         <div>
  7.             <span>{n}</span>
  8.             <button
  9.                 onClick={() => {
  10.                     // setN(n + 1)
  11.                     // setN(n + 1) // 此时,n的值仍然是0
  12.                     setN((prevN) => prevN + 1);
  13.                     setN((prevN) => prevN + 1);
  14.                 }}
  15.             >
  16.                 +
  17.             </button>
  18.         </div>
  19.     );
  20. }
复制代码

以上。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

曂沅仴駦

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表