useState原理

简介: 每个函数组件对应一个React节点每个节点保存着state和index (这个state可能描述不准确,但主要是让大家想清楚这个事情,应该是一个类似state的东西)useState会读取state[index]index由useState出现的顺序决定setState会修改State,并触发更新

useState用法

脑补一下点击button后会发生什么

function App() {
  const [n, setN] = React.useState(0);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
    </div>
  );
}

会使页面上的n变量由0变成1

71604b3e9f920719707d9a6efc82bc1.png

脑补之后

问自己几个问题

执行setN的时候会发生什么?n会变吗?App()会重新执行吗?

如果App()会重新执行,那么useState(0)的时候,n每次的值会有不同吗?

通过console.log你就能得到答案

分析

setN

setN一定会修改数据x,(我们暂且将这个不知道的东西称为x),将n+1存入x

setN一定会触发<App/>重新渲染(render)

useState

useState肯定会从x读取到n的最新值

x

每个组件有自己的数据x,我们将其命名为state

尝试实现React.useState

function myUseState(initialValue) {
  var state = initialValue;
  function setState(newState) {
    state = newState;
    render();
  }
  return [state, setState];
}
// render方法我们就不实现了,直接让它渲染
const render = () => ReactDOM.render(<App />, rootElement);
function App() {
  const [n, setN] = myUseState(0);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
    </div>
  );
}

完全没有变化啊

因为myUseState会将state重置

我们需要一个不会被myUseState重置的变量

那么这个变量只要声明在myUseState外面即可

// ***********************************
let _state;
// ***********************************
function myUseState(initialValue) {
  _state = _state === undefined ? initialValue : _state;
  function setState(newState) {
    _state = newState;
    render();
  }
  return [_state, setState];
}
const render = () => ReactDOM.render(<App />, rootElement);
function App() {
  const [n, setN] = myUseState(0);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
    </div>
  );
}

useState就这么简单?

别急,还有问题

如果一个组件用了两个useState怎么办?

由于所有数据都方在_state,所以会冲突

改进思路

把_state做成一个对象

比如_state = { n:0, m:0}

不行,因为useState(0)并不知道变量叫n还是m

把_state做成数组

比如_state= [ 0, 0 ]

貌似可行,我们来试试看

多个useState

// ***********************************
let _state = [];
let index = 0;
// ***********************************
function myUseState(initialValue) {
  const currentIndex = index;
  index += 1;
  _state[currentIndex] = _state[currentIndex] || initialValue;
  const setState = newState => {
    _state[currentIndex] = newState;
    render();
  };
  return [_state[currentIndex], setState];
}
const render = () => {
  index = 0;
  ReactDOM.render(<App />, rootElement);
};
function App() {
  const [n, setN] = myUseState(0);
  const [m, setM] = myUseState(0);
  console.log(_state);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
      <p>{m}</p>
      <p>
        <button onClick={() => setM(m + 1)}>+1</button>
      </p>
    </div>
  );
}

_state数组方案缺点

useState调用顺序

如果第一次渲染时,n是第一个,m是第二个,k是第三个

则第二次渲染时必须保证顺序完全一致

所以React不允许出现如下代码

2 ReactDOM . render (< cApp />, rootElement ):
25
 Function App (){
 const [ n , setN ] React . useState (0); let m , setM ;
 if ( n %2-1)
[ m , setM ]= React . useState (0): return (
 cdiv className -" App ">< p > fnj </ p >
< button onC1ick={()=> setN ( n .1))>+1</ button >
Console wos cleored 
 Uncaught Invariant Violation : Rendered more hooks than during the previous render .
 invariant (https://j6y72.csb.anp/no
 odules / react - dom / cjs / react - dom . develonment . js :55:15)
 updateworkinProgressHook (httR5i/Z1by72.csb. anp / node moduies / react - gon /c3sreact- gom . oeveopn 
 updateReducer (https://16y72.csb.app/nodem
modu1es/ react - dom /c1s/ react - dom .deye1ooment.1s1139991
 nt .1s:13294:10)

总结

  1. 每个函数组件对应一个React节点
  2. 每个节点保存着stateindex (这个state可能描述不准确,但主要是让大家想清楚这个事情,应该是一个类似state的东西)
  3. useState会读取state[index]
  4. indexuseState出现的顺序决定
  5. setState会修改State,并触发更新



目录
相关文章
|
前端开发 JavaScript 安全
useEffect 与 useLayoutEffect区别
useEffect 与 useLayoutEffect区别
79 0
|
22天前
|
存储 前端开发 JavaScript
React useState 和 useRef 的区别
本文介绍了 React 中 `useState` 和 `useRef` 这两个重要 Hook 的区别和使用场景。`useState` 用于管理状态并在状态变化时重新渲染组件,适用于表单输入、显示/隐藏组件、动态样式等场景。`useRef` 则用于在渲染之间保持可变值而不触发重新渲染,适用于访问 DOM 元素、存储定时器 ID 等场景。文章还提供了具体的代码示例,帮助读者更好地理解和应用这两个 Hook。
32 0
|
2月前
|
缓存 前端开发
React中函数式Hooks之memo、useCallback的使用以及useMemo、useCallback的区别
React中的`memo`是高阶组件,类似于类组件的`PureComponent`,用于避免不必要的渲染。`useCallback` Hook 用于缓存函数,避免在每次渲染时都创建新的函数实例。`memo`可以接收一个比较函数作为第二个参数,以确定是否需要重新渲染组件。`useMemo`用于缓存计算结果,避免重复计算。两者都可以用来优化性能,但适用场景不同:`memo`用于组件,`useMemo`和`useCallback`用于值和函数的缓存。
77 1
|
4月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
88 1
|
6月前
|
前端开发 JavaScript
React中的状态管理:useState与useReducer的使用与探讨
【4月更文挑战第25天】本文探讨了React中构建动态界面的关键——状态管理,重点关注`useState`和`useReducer` Hook。`useState`适用于简单状态管理,例如计数器,而`useReducer`在处理复杂逻辑和多个状态更新时更具优势,提供更好的组织和可维护性。选择使用哪个取决于状态逻辑复杂度、可维护性和性能需求。合理运用这两个工具能实现高效、可维护的React应用。
|
6月前
|
存储 前端开发 JavaScript
React Hooks实战:从useState到useContext深度解析
React Hooks 深度解析:useState用于函数组件的状态管理,通过初始化和更新状态实现渲染控制;useContext则提供跨组件数据传递。useState的状态更新是异步的,不支持浅比较,可结合useEffect处理副作用。useContext在多层组件间共享状态,但可能导致不必要的渲染。两者结合可创建复杂应用场景,如带主题切换的计数器。了解其工作原理和优化策略,能有效提升React应用性能。
90 0
|
JavaScript
useEffect和useLayoutEffect有什么区别
useEffect和useLayoutEffect有什么区别
|
6月前
|
前端开发
说说React中setState和replaceState的区别?
在 React 中,setState()和 replaceState()是用于更新组件状态的两个方法。它们之间有一些区别
44 0
|
11月前
|
存储 前端开发 JavaScript
useRef 和 useState 哪个更好?
useRef 和 useState 哪个更好?
94 1
|
6月前
|
前端开发 JavaScript
useState和useReducer的区别?
useState和useReducer的区别?
125 0