React状态State

543 阅读2分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」。

这是React清风拂面系列第六篇,上一篇请看这里

为什么需要状态

import { sculptureList } from './data.js';

export default function Gallery() {
  let index = 0;

  function handleClick() {
    index = index + 1;
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleClick}>
        Next
      </button>
       <h2>
        <i>{sculpture.name} </i> 
        by {sculpture.artist}
      </h2>
    </>
  );
}

先看上面的代码,完整演示这里 handleClick 的本意是想切换数组里面的下一个对象,但是上面的代码无法达到目的。

主要原因在于:

  1. 本地变量index无法再2次渲染间保持状态。React每次刷新组件都是重置,因为index始终是初始值。
  2. 上面的写法无法触发React组件的render函数,也就是无法触发重新渲染。

所以,这里需要一个特殊的函数来满足上面两个要求useState.

useState 符合下面2个条件:

  1. 在多次渲染之间可以保持状态,不会因为每次刷新而重置。
  2. 可以触发React的render函数,更新视图。

用法

const [index, setIndex] = useState(0);

之前文章说过,useState传入的值是index的默认值。index是变量,setIndex是更新index的函数。

代码改成下面结构,完整看这里

import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);

  function handleClick() {
    setIndex(index + 1);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i> 
        by {sculpture.artist}
      </h2>
    </>
  );
}

第一个Hook

useState是你碰到的第一个Hook,在React里面Hook是一大类,都是以use开头如useXX的函数。

Hooks是一种特殊的函数,与React框架产生紧密联系。

Hooks的规则:

  1. 以use开头。
  2. 放在函数的头部,无法放在条件判断,循环或者内嵌等。

如果你违反规则,React库会报错。

多个state变量

可以用useState 定义多个变量,代码这里


    export default function Gallery() {
      const [index, setIndex] = useState(0);
      const [showMore, setShowMore] = useState(false);
   }

多个变量还是都放在一个对象里面,主要看变量之间是否有关联,如果是内聚性高,就比较合适放在一个对象。

这里面我们定义了2个useState,如果说我们调用setShowMore(index)React能查出这个错误呢。答案是不能。

因为 React Hooks 本质上是数组,我们每次调用useState,就是移动数组里面的下标。

Hooks源码简化版

let componentHooks = [];
let currentHookIndex = 0;

function useState(initialState) {
  let pair = componentHooks[currentHookIndex];
  if (pair) {
    currentHookIndex++;
    return pair;
  }

   //将函数入参当做默认值
  pair = [initialState, setState];

   //setState接受入参保存为下一次的state,更新Dom。
  function setState(nextState) {
    pair[0] = nextState;
    updateDOM();
  }

   
  //保存到数组
  componentHooks[currentHookIndex] = pair;
  currentHookIndex++;
  return pair;
}

另外,state属于函数的组件的私有变量,初始化多个组件实例,state之间不影响。

具体可看这个例子

import Gallery from './Gallery.js';

export default function Page() {
  return (
    <div className="Page">
      <Gallery />
      <Gallery />
    </div>
  );
}

pic