我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

在本文中,苏南大叔对ReactuseState()钩子做个简单的总结,总结的目的主要是引出useState()存在的问题,为后续文章提出的可能的解决方案,做伏笔铺垫。

苏南大叔:React教程,函数组件状态管理useState/useReducer总结 - usestate状态管理总结
React教程,函数组件状态管理useState/useReducer总结(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react@19.0.0useState()是目前的React项目中,最最常用的钩子。

前文回顾

在传统类组件中,可以使用state,参考文章:

在函数组件里面,通过useState()使用state的方法。参考文章:

React官方出品的useReducer()钩子,对useState()钩子的一个升级使用方式,参考文章:

useState()简单使用

import React, { useState } from "react";
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      {count}
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount( state  => state + 2)}>+2</button>
      <button onClick={() => setCount((state) => state + 3)}>[推荐方式]+3</button>
    </>
  );
};
export default App;

这里推荐的写法就是:

() => setCount((state) => state)}

useState()进阶使用

这里主要是利用...运算,修改稍微复杂的对象。代码参考:

import React, { useState } from "react";
const App = () => {
  let [info, setInfo] = useState({
    name: "苏南大叔",
    city: "beijing",
  });
  return (
    <>
      {info.name},{info.city}
      <button
        onClick={() => {
          info.city = "yanjiao"; // 无效不会改变的
          setInfo(info); // 这个也无效
        }}
      >
        修改city,但是无效
      </button>
      <button onClick={() => setInfo({ ...info, city: "tangshan" })}>
        对象改变,但不推荐
      </button>
      <button
        onClick={() => {
          setInfo((info) => {
            return { ...info, name: "sunan大叔" };
          });
        }}
      >
        推荐写法
      </button>
      <button
        onClick={() => {
          setInfo({
            name: "苏南大叔",
            city: "beijing",
          });
        }}
      >
        重置
      </button>
    </>
  );
};
export default App;

苏南大叔:React教程,函数组件状态管理useState/useReducer总结 - setinfo用法
React教程,函数组件状态管理useState/useReducer总结(图3-2)

useState()最经典案例

最经典的useState()的例子,setInterval()+useState()+稍复杂对象。

import React, { useState, useEffect, useRef } from "react";
function Timer() {
  const [seconds, setSeconds] = useState({ s: 0 });
  const intervalRef = useRef(null);
  const a = () => {
    setSeconds((seconds) => {
      return {
        ...seconds,
        ...{ s: seconds.s + 1 },
      };
    });
  };
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      a();
    }, 1000);
    return () => clearInterval(intervalRef.current);
  }, []); // 组件挂载时执行
  return <div>Seconds: {seconds.s}</div>;
}
export default Timer;

这个例子就是对上面两个例子的结论肯定。尽量使用setState((state)=>{}),内部使用...对状态进行展开。如果不遵守这个规则的话,这个setInterval()的例子就无法正常运行。

useReducer()改写

这里使用React官方的useReact()的升级版useReducer()方案,再次改写上面的特殊例子。

import React, { useReducer, useEffect, useRef } from "react";
const reducer = (state, action) => {
  switch (action.type) {
    case "name":
      return { ...state, ...{ name: action?.name } };
    case "gold":
      return { ...state, ...{ gold: state?.gold + 1 } };
    case "reset":
      return { ...action?.info };
    default:
      throw new Error("未识别操作");
  }
};
function App() {
  const [info, dispatch] = useReducer(reducer, {
    name: "Uncle sunan",
    gold: 10000,
  });
  const intervalRef = useRef(null);
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      dispatch({ type: "gold" });
    }, 1000);
    return () => clearInterval(intervalRef.current);
  }, []); // 组件挂载时执行
  return (
    <>
      {info.name},{info.gold}
      <button
        onClick={() => {
          dispatch({ type: "name", name: "苏南大叔" });
        }}
      >
        name
      </button>
      <button
        onClick={() => {
          dispatch({
            type: "reset",
            info: { name: "Uncle sunan", gold: 10000 },
          });
        }}
      >
        reset
      </button>
    </>
  );
}
export default App;

这个例子的成功运行,表明:因为useReducer是强制使用state变量的。所以,遵守规则的前提下(也就是说在reducer内部使用state),setInterval()useReducer()是不会产生冲突的。变量是可以正常更新的。

苏南大叔:React教程,函数组件状态管理useState/useReducer总结 - useReducer
React教程,函数组件状态管理useState/useReducer总结(图3-3)

结语

更多react例子,请参考苏南大叔的博客文章:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react