前言
在项目代码中,尝试了在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代码,也同样能够保存函数状态。