React组件保存函数状态所引发的一系列问题

本文探讨了在React组件中使用useState和useRef保存函数状态时遇到的问题。作者发现直接使用useState初始化函数会导致函数立即执行,并解释了这是由于React的惰性初始State机制。通过调整代码,作者展示了如何正确使用useState和useRef来保存和更新函数状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在项目代码中,尝试了在React组件中对函数状态进行一个保存,但出现了一系列错误,这篇文章将相应代码抽象到codesandbox上进行学习和记录。
在这里插入图片描述


一、出现问题

问题1

import "./styles.css";
import react from "react";
import { useState } from "react";

export default function App() {
  const [callback, setCallback] = useState(() => {
    alert("init success");
  });
  return (
    <div className="App">
    </div>
  );
}

以上代码是codesandbox上的代码,我本想通过上述代码实现函数callback状态的保存,结果初始化了callback函数,就立刻执行了callback函数。
在这里插入图片描述

问题2

在这里插入图片描述
如上图所示,callback的类型为void,按照我今天之前的认识,useState用泛型可以推断我们传入的类型,所以我们传入一个函数,那么callback的类型‘理应’被推断成函数,结果是void。

问题3

import "./styles.css";
import react from "react";
import { useState } from "react";

export default function App() {
  const [callback, setCallback] = useState(() => {
    alert("init success");
  });
  return (
    <div className="App">
      <button onClick={() => setCallback(alert("set"))}>
        click
      </button>
    </div>
  );
}

点击click按钮后,"set"直接被alert出来,而不是更新这个函数状态。在这里插入图片描述


二、学习

1.useState

在这里插入图片描述
通过查看useState函数签名可以看到,其签名是一个联合类型,可以传入S,或者传入一个箭头函数。

2.惰性初始State

initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用:

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

通过官网文档,学习了惰性初始State的概念,这样看来,以上问题也就迎刃而解了。
const [callback, setCallback] = useState(() => { alert("init success"); });中我传入的函数被useState认为要惰性初始化state,因此便执行我所传入的函数,企图拿到一个initailState的这个返回值赋予callback,因此才会有初始化callback状态时,便弹出了"init success"弹窗,且惰性初始state只会在组件初始渲染的时候执行一次,后续渲染都不起作用。同时由于该函数没有返回值,因此callback的类型被认为是void.在之后onclick事件执行时,没有更新函数状态,而是执行传入的函数想要企图拿到一个state返回值。

进一步验证

参考惰性初始state,对代码进行如下更改:

import "./styles.css";
import react from "react";
import { useState } from "react";

export default function App() {
  const [callback, setCallback] = useState(() => {
    return "第一次渲染:callback1";
  });
  return (
    <div className="App">
      {callback}
      <button onClick={() => setCallback(() => "点击按钮:callback2")}>
        click
      </button>
    </div>
  );
}

验证结果

在这里插入图片描述
在这里插入图片描述
破案!以上结果符合惰性初始State。
当我用最初的代码来试图保存函数状态时候,React并不会认为我是在初始函数状态,而是会认为我是在惰性初始State,在我执行setCallback时,React不会认为我对函数状态进行更新,而是以为我对惰性值进行更新。那应该怎么实现函数状态的保存呢?


三、实现

用useState实现函数状态保存

利用惰性初始state的原理进行函数状态的保存

import "./styles.css";
import react from "react";
import { useState } from "react";

export default function App() {
  const [callback, setCallback] = useState(() => () => {
    alert("inint success");
  });
  return (
    <div className="App">
      <button onClick={() => setCallback(() => () => alert("update success"))}>
        setCallback
      </button>
      <button onClick={callback}>callback()</button>
    </div>
  );
}

第一次点击callback()按钮执行初始化的callback函数
在这里插入图片描述
然后店家setCallback按钮后,更新callback函数状态。
再次点击callback()按钮
在这里插入图片描述

用useRef实现函数状态保存

import "./styles.css";
import react from "react";
import { useRef } from "react";

export default function App() {
  const callbackRef = useRef(() => alert("init success"));
  const callback = callbackRef.current;
  return (
    <div className="App">
      <button
        onClick={() => (callbackRef.current = () => alert("update success"))}
      >
        setCallback
      </button>
      <button onClick={() => callbackRef.current()}>callback()</button>
    </div>
  );
}

用上述useRef代码,也同样能够保存函数状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值