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

Posted

技术标签:

【中文标题】是否可以在 React 中使用 React.useState(() => )?【英文标题】:is it possible to React.useState(() => ) in React?是否可以在 React 中使用 React.useState(() => )? 【发布时间】:2019-09-01 10:09:49 【问题描述】:

是否可以使用 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

【问题讨论】:

【参考方案1】:

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

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 在设置时接受一个函数,但需要知道将函数包装在函数中以便将其存储为状态充其量是不直观的。谢谢你,谢谢你,谢谢你!永远不会想出这个... 这也是我的救命稻草。我的问题是我设置为状态变量的函数在没有被调用的情况下被触发。将其存储为返回该函数的函数就像一个魅力。我同意这在反应文档中的任何地方都没有记录。谢谢! 也许这些在过去没有记录,但现在已经记录了。请参阅Lazy initial state 部分,以及上面关于合并更新的黄色框,也就是使用prevState。我还发现这篇文章很有帮助:medium.com/swlh/…【参考方案2】:

TL;DR

是的,可以使用函数作为 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 with types 中的签名是

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

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

    按原样提供初始值(React.useState(0) - 初始值0), 提供一个函数,该函数返回要设置的初始值(React.useState(() =&gt; 0) - 初始值也是0)。

需要注意的是:如果你在React.useState中提供了一个函数,那么这个函数就会被执行,当React.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时,外部函数肯定会被执行,并存储它的返回值。 由于此返回值现在是您需要的函数,因此将存储此函数

关于状态设置函数的说明

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

Dispatch<SetStateAction<S>>

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

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

【讨论】:

【参考方案3】:

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

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

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

【讨论】:

以上是关于是否可以在 React 中使用 React.useState(() => )?的主要内容,如果未能解决你的问题,请参考以下文章

[React] Use the new React Context API

[React] Use React.cloneElement to Modify and Add Additional Properties to React Children

[React] Use a Render Porp

[React] Use the React Effect Hook in Function Components

[React] Use React Context to Manage Application State Through Routes

[React] Use the URL as the source of truth in React