在Javascript和Typescript中,(箭头(函数应该是一等公民。因此,我希望我可以在我的 React 状态中拥有函数类型。然而,React HookuseState
似乎不能很好地处理函数类型。
我有以下代码:
import React, { useState } from "react";
function callApi(num: number): number {
console.log(`Api called with number ${num}. This should never happen.`);
return num;
}
type Command = () => number;
function Foo() {
const [command, setCommand] = useState<Command>();
console.log(`command is ${command}.`);
// ####################
const handleButtonClick = () => {
console.log("Button clicked.");
const myCommand = () => callApi(42);
setCommand(myCommand);
};
// ####################
return (
<div>
<button onClick={handleButtonClick}>Change state</button>
</div>
);
}
export default Foo;
在此代码沙盒中
当我访问该页面并单击按钮时,我得到以下控制台输出:
command is undefined.
Button clicked.
Api called with number 42. This should never happen.
command is 42.
因此,可以看到,尽管在我的按钮处理程序中,状态变量command
应该设置为新的箭头函数,但 React 并没有这样做。相反,它执行新的箭头函数并将结果存储在状态变量中。
为什么会这样,我如何在 React 状态下存储函数而不必使用一些不方便的包装器对象?
对于上下文:通常,通过各种用户输入构建某些命令函数并将它们存储在状态中以供以后使用会很方便,例如在构建作业队列时。
为什么会这样,我如何在 React 状态下存储函数而不必使用一些不方便的包装器对象?
为什么?
React 的useState
接受一个函数(它将用作获取状态当前值的回调(或一个值,所以如果你传递() => callApi(42)
它会理解它,就像您希望新状态在传入42
时成为callApi
的返回值一样。
你能做什么?
如果你真的需要这样做(在状态中存储函数(,你可以做一些类似useCommand(() => myCommand)
.
但是,我建议您不要将函数存储在组件的状态中。
如果在代码中的某些内容发生更改时需要函数的新实例(或新函数(,请改用useCallback
或useMemo
。
每当更改依赖项数组中指定的值之一时,两者都将创建一个新函数。
当它们的依赖项更改时,useCallback
将创建一个新函数,因此您可以像以下方式使用它:
function Button() {
const [buttonAction, setButtonAction] = useState(null);
// dynamicHandler will be a new function every time buttonAction changes
const dynamicHandler = useCallback(() => {
// Logic here based on the buttonAction value
}, [buttonAction]);
const handleClick = () => {
setButtonAction(BUTTON_ACTIONS.DO_SOMETHING);
};
return (
<button onClick={handleClick} />
);
}
查看useCallback
文档。
您可以将函数存储为对象
setCommand({ function:()=>callApi(42) })
然后当你想调用存储在 state 中的函数时,你可以简单地做command.function()