首页 > 解决方案 > 如何使用 React Hook useState 存储函数类型(例如箭头函数)的值?

问题描述

在 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;

这个 Codesandbox

当我访问该页面并单击按钮时,我得到以下控制台输出:

command is undefined. 
Button clicked. 
Api called with number 42. This should never happen. 
command is 42. 

因此,可以看到虽然在我的按钮处理程序中,状态变量command应该设置为一个新的箭头函数,但 React 并没有这样做。相反,它执行新的箭头函数并将结果存储在状态变量中。

为什么会这样?如何在 React 状态下存储函数,而不必使用一些不方便的包装对象?

对于上下文:通常通过各种用户输入来构建某些命令功能并将它们存储在状态中以供以后使用会很方便,例如在构建作业队列时。

标签: reactjstypescriptreact-hooks

解决方案


为什么会这样?如何在 React 状态下存储函数,而不必使用一些不方便的包装对象?

为什么?

ReactuseState接受一个函数(它将用作获取状态当前值的回调)或一个值,因此如果您传递() => callApi(42)它,它将理解它就像您希望新状态成为callApi传入时的返回值一个42

你能做什么?

如果你真的需要这样做(在状态中存储一个函数),你可以做类似useCommand(() => myCommand).

但是,我建议您不要将函数存储在组件的状态中。

如果您在代码中的某些内容发生更改时需要函数的新实例(或新函数),请使用useCallbackoruseMemo代替。

无论何时更改依赖项数组中指定的值之一,都将创建一个新函数。

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 文档


推荐阅读