为什么“useState"钩子在是函数引用时调用初始状态? [英] Why does the 'useState' hook invoke the initial state when it's a function reference?

查看:19
本文介绍了为什么“useState"钩子在是函数引用时调用初始状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

React 有一个名为 useState 的钩子,它在向功能组件.

Hooks API 参考 指出:

<块引用>

useState:

const [state, setState] = useState(initialState);

返回一个有状态的值,以及一个更新它的函数.

在初始渲染期间,返回的状态 (state) 与作为第一个参数传递的值 (initialState) 相同.

setState 函数用于更新状态.它接受一个新的状态值并将组件的重新渲染排入队列.

React 文档 指出:

<块引用>

我们将什么作为参数传递给 useState?

useState() 钩子的唯一参数是初始状态.与类不同,状态不必是对象.如果这就是我们所需要的,我们可以保留一个数字或一个字符串.在我们的示例中,我们只需要用户点击次数的数字,因此将 0 作为我们变量的初始状态传递.(如果我们想在 state 中存储两个不同的值,我们会调用 useState() 两次.)

意外行为:

但是,我注意到了一些奇怪的、似乎没有记录的行为.

如果我尝试使用 useState 钩子将函数存储为状态,react 将调用函数引用.例如

const任意函数 = () =>{console.log("我被调用了!");返回 100;};const MyComponent = () =>{//尝试存储字符串 - 按预期工作:const [网站,setWebsite] = useState("stackoverflow");//存储字符串console.log(网站类型);//打印字符串"控制台日志(网站);//打印stackoverflow"//尝试存储一个函数 - 没有按预期工作:const [fn, setFn] = useState(arbitraryFunction);//打印我被调用了!"console.log(typeof fn);//打印数字"(期望函数")控制台日志(fn);//打印100"返回空;//不需要为这个例子渲染任何东西...};

当我们调用 useState(arbitraryFunction) 时,react 会调用 arbitraryFunction 并使用它的返回值作为状态.

作为一种解决方法:

我们可以通过将我们的函数引用包装在另一个函数中来将函数存储为状态.例如

const [fn, setFn] = useState(() =>任意函数)

我还没有遇到任何将函数存储为状态的现实原因,但有人明确选择以不同方式处理函数参数似乎很奇怪.

这个选项可以在 React 代码库的多个地方看到:

initialState = typeof initialArg === 'function' ?initialArg() : initialArg;

为什么会存在这个看似无证的功能?

我想不出任何人想要/期望调用他们的函数引用的任何充分理由,但也许你可以.

如果有记录,记录在哪里?

解决方案

这是记录在案的 此处:

<块引用>

延迟初始状态

initialState 参数是初始渲染期间使用的状态.在随后的渲染中,它被忽略.如果初始状态是昂贵计算的结果,您可以提供一个函数相反,它只会在初始渲染时执行:

const [state, setState] = useState(() => {const initialState = someExpensiveComputation(props);返回初始状态;});

将回调传递给 setState 也调用回调,但出于不同的原因:

<块引用>

功能更新

如果新状态是使用之前的状态计算出来的,你可以传递一个函数设置状态.该函数将接收先前的值,并返回一个更新的值.这是一个计数器组件的例子使用两种形式的 setState:

function Counter({initialCount}) {const [count, setCount] = useState(initialCount);返回 (<>计数:{计数}<button onClick={() =>setCount(initialCount)}>重置</button><button onClick={() =>setCount(prevCount => prevCount - 1)}>-</button><button onClick={() =>setCount(prevCount => prevCount + 1)}>+</>);}

React has a hook called useState, which is used when adding state to functional components.

The Hooks API Reference states:

useState:

const [state, setState] = useState(initialState);

Returns a stateful value, and a function to update it.

During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

The React Documentation states:

What do we pass to useState as an argument?

The only argument to the useState() Hook is the initial state. Unlike with classes, the state doesn’t have to be an object. We can keep a number or a string if that’s all we need. In our example, we just want a number for how many times the user clicked, so pass 0 as initial state for our variable. (If we wanted to store two different values in state, we would call useState()twice.)

Unexpected behaviour:

However, I've noticed some strange, seemingly undocumented, behaviour.

If I try to use the useState hook to store a function as state, react will invoke the function reference. e.g.

const arbitraryFunction = () => {
    console.log("I have been invoked!");
    return 100;
};

const MyComponent = () => {

    // Trying to store a string - works as expected:
    const [website, setWebsite] = useState("stackoverflow"); // Stores the string
    console.log(typeof website);                             // Prints "string"
    console.log(website);                                    // Prints "stackoverflow"

    // Trying to store a function - doesn't work as expected:
    const [fn, setFn] = useState(arbitraryFunction);         // Prints "I have been invoked!"
    console.log(typeof fn);                                  // Prints "number" (expecting "function")
    console.log(fn);                                         // Prints "100"

    return null; // Don't need to render anything for this example...
};

When we call useState(arbitraryFunction), react will invoke arbitraryFunction and use its return value as the state.

As a workaround:

We can store functions as state by wrapping our function reference in another function. e.g.

const [fn, setFn] = useState(() => arbitraryFunction)

I haven't yet come across any real-world reasons to store functions as state, but it seems weird that somebody made the explicit choice to treat function arguments differently.

This choice can be seen in multiple places throughout the React codebase:

initialState = typeof initialArg === 'function' ? initialArg() : initialArg;

Why does this seemingly undocumented feature exist?

I can't think of any good reasons why anybody would want/expect their function reference to be invoked, but perhaps you can.

If this is documented, where is it documented?

解决方案

This is documented here:

Lazy initial state

The initialState argument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render:

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

Passing a callback to setState also calls the callback, but for a different reason:

Functional updates

If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value. Here’s an example of a counter component that uses both forms of setState:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

这篇关于为什么“useState"钩子在是函数引用时调用初始状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆