是否可以在 React 中使用 React.useState(() => {}) ?

IT技术 reactjs typescript default-value react-hooks
2021-04-03 23:46:59

是否可以使用 afunction作为我的 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 oopsotrher ooops将立即记录到控制台,Show Ooops再次单击后不会记录

为什么 ?

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

或者 React 有其特殊的处理方式the function state

3个回答

可以使用钩子将函数设置为状态,但是因为可以使用返回初始状态或更新状态的函数来初始化和更新状态,所以您需要提供一个函数,该函数又返回您想要放入的函数状态。

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>

这绝对是救命稻草!而且,据我所知,没有证件。无法弄清楚为什么我存储的函数没有执行。我喜欢 setState 在设置时接受一个函数,但需要知道将一个函数包装在一个函数中以便将它存储为状态充其量是不直观的。谢谢你,谢谢你,谢谢你!永远不会想到这一点......
2021-06-09 23:46:59
这对我来说也是救命稻草。我的问题是我设置为状态变量的函数在没有被调用的情况下触发。将它存储为返回该函数的函数就像一个魅力。我同意在 react 文档中的任何地方都没有记录这一点。谢谢!
2021-06-11 23:46:59
也许这些在过去没有记录,但现在有了。请参阅延迟初始状态部分,以及其上方关于合并更新的黄色框,也就是使用prevState. 我还发现这篇文章很有帮助:medium.com/swlh/...
2021-06-16 23:46:59

TL; 博士

是的,可以使用函数作为 React 组件的状态。为了做到这一点,就必须使用函数返回你的函数React.useState

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

// or

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

要更新您的函数,您还必须使用返回您的函数的函数

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

// or

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

详细解答

关于的注意事项 React.useState

useState带有类型的 React 中的签名

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

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

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

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

如何实际存储函数

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

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

'default ooops'React.useState调用时立即记录undefined存储返回值(在本例中)。

这可以通过提供一个高阶函数返回您要存储的函数避免

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

这样外部函数在第一次运行时肯定会被执行,React.useState并且它的返回值将被存储。由于此返回值现在是您需要的函数,因此将存储此函数

关于 state setter 函数的注意事项

状态设置器函数的(此处setOoops)签名为

Dispatch<SetStateAction<S>>

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

就像在React.useState那里也有可能用一个值或一个返回值的函数来更新状态。因此,为了更新状态,还必须使用上面的高阶函数

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

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

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