在 React 中可以 React.useState(() => {}) 吗?

is it possible to React.useState(() => {}) in React?

是否可以使用 function 作为我的 React 组件的状态?

示例代码在这里:

// typescript 
type OoopsFunction = () => void;

export function App() {
    const [ooops, setOoops] = React.useState<OoopsFunction>(
        () => console.log('default ooops')
    );

    return (
        <div>
            <div onClick={ ooops }>
                Show Ooops
            </div>

            <div onClick={() => {
                setOoops(() => console.log('other ooops'))
            }}>
                change oops
            </div>
        </div>
    )
}

但它不起作用...defaultOoops 将在一开始被调用,当单击 change oops 时,otrher ooops 将立即记录到控制台而不是记录再次点击 Show Ooops 后。

为什么?

我可以使用函数作为组件的状态吗?

否则 React 有其特殊的方式来处理这样的 the function state

可以使用钩子在状态中设置一个函数,但是因为可以使用 returns 初始状态或更新状态的函数来初始化和更新状态,所以您需要提供一个函数,在将 returns 函数置于状态。

const { useState } = React;

function App() {
  const [ooops, setOoops] = useState(() => () => console.log("default ooops"));

  return (
    <div>
      <button onClick={ooops}>Show Ooops</button>

      <button
        onClick={() => {
          setOoops(() => () => console.log("other ooops"));
        }}
      >
        change oops
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

TL;DR

是的,可以使用函数作为 React 组件的状态。为此,您必须React.useState:

中return使用函数
const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => () => console.log('default ooops')
);

// or

const yourFunction = () => console.log('default ooops');
const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => yourFunction
);

要更新您的函数,您还必须使用一个函数return您的函数:

setOoops(() => () => console.log("other ooops"));

// or

const otherFunction = () => console.log("other ooops");
setOoops(() => otherFunction);

详细解答

关于 React.useState

的注释

React with types useState 的签名是

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

它表明,有两种方法可以在您的状态下设置初始值:

  1. 按原样提供初始值(React.useState(0) - 初始值0),
  2. 提供一个函数,其中returns要设置的初始值(React.useState(() => 0) - 初始值也0)。

需要注意的是:如果你在React.useState中提供了一个函数,那么这个函数就会被执行,当React.useState被执行并且returned的值为存储为初始状态。

如何实际存储函数

这里的问题是,如果您想将函数存储为状态,则不能按原样提供它作为初始状态,因为这会导致 函数被执行及其 return 值存储为状态而不是函数本身。因此当你写

const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => console.log('default ooops')
);
当调用 React.useState 并存储 return 值(在本例中为 undefined)时,会立即记录

'default ooops'

这可以通过提供更高阶的函数来避免return你想要存储的函数:

const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => () => console.log('default ooops')
);

这样外层函数肯定会在第一个运行 React.useState 时执行,它的return 值将被存储。 由于此 return 值现在是您所需的函数,因此将存储此函数

关于状态 setter 函数的注释

状态 setter 函数(此处 setOoops)的签名为

Dispatch<SetStateAction<S>>

type Dispatch<A> = (value: A) => void;
type SetStateAction<S> = S | ((prevState: S) => S);

React.useState 一样,也可以使用值或 returning 值的函数来更新状态。 因此,为了更新状态,还必须使用上面的高阶函数

之前的答案让我走上了正确的轨道,但我需要稍微调整我的 setState 参数,因为我想执行一个带有参数的完整函数。以下对我有用!

const [handler, setHandler] = useState(() => {});

setHandler(() => () => enableScheduleById(scheduleId));