Javascript 在react功能组件中,setState的功能语法有何用途?

Javascript 在react功能组件中,setState的功能语法有何用途?,javascript,reactjs,Javascript,Reactjs,我们讨论的是具有useState 比方说 const[age,setAge]=useState(0) 现在让我们说,在更新age时,我必须使用以前的age React文档提到一个调用,您可以在其中传递一个函数,该函数的参数将是状态的前一个值,例如 setState((以前的)=>previousAge+1) 既然我能做到,为什么我要这么做 setState(以前的+1) 使用functionalsetState有什么好处 我知道在基于类的组件中,有一种叫做批处理状态更新的功能性方法, 但是我在功

我们讨论的是具有
useState

比方说

const[age,setAge]=useState(0)

现在让我们说,在更新
age
时,我必须使用以前的
age

React文档提到一个调用,您可以在其中传递一个函数,该函数的参数将是状态的前一个值,例如

setState((以前的)=>previousAge+1)

既然我能做到,为什么我要这么做

setState(以前的+1)

使用functional
setState
有什么好处

我知道在基于类的组件中,有一种叫做批处理状态更新的功能性方法,
但是我在功能组件文档中找不到类似的东西。

因为如果你不这样做,会在某个时候发现你得到了
年龄的旧值。问题是,有时候你的建议会奏效。但有时不会。它今天可能不会打断您当前的代码,但可能会打断您几周前编写的其他代码,或者几个月后打断您当前的代码

症状真的很奇怪。您可以使用
{x}
语法打印jsx组件内部的变量值,以后使用
控制台打印相同的变量。在渲染jsx组件(而不是之前)后,使用
日志打印相同的变量然后发现
console.log
值已过时-渲染后发生的
console.log
值可能比渲染时的值旧


因此,状态变量的实际值可能并不总是在常规代码中正常工作-它们仅用于在渲染中返回最新值。因此,状态设置器中的回调机制被实现为允许您在呈现外部的常规代码中获取状态变量的最新值。

根据调用设置器的速度/频率,可能会出现问题

如果使用的是从闭包中获取值的简单方法,则两个渲染之间的后续调用可能不会达到预期效果

一个简单的例子:

function App() {
    const [counter, setCounter] = useState(0);
    const incWithClosure = () => {
        setCounter(counter + 1);
    };
    const incWithUpdate = () => {
        setCounter(oldCounter => oldCounter + 1);
    };

    return (<>
        <button onClick={_ => { incWithClosure(); incWithClosure(); }}>
            Increment twice using incWithClosure
        </button>
        <button onClick={_ => { incWithUpdate(); incWithUpdate(); }}>
            Increment twice using incWithUpdate
        </button>
        <p>{counter}</p>
    </>);
}

单击第一个按钮两次(在1秒内),观察计数器仅增加1。第二个按钮具有正确的行为。

它们不相同,如果您的更新依赖于在状态中找到的以前的值,则应使用函数形式。如果在这种情况下不使用函数形式,那么代码有时会中断

它为什么会断开以及何时断开

React功能组件只是闭包,闭包中的状态值可能已过时-这意味着闭包中的值与该组件处于React状态的值不匹配,在以下情况下可能会发生这种情况:

1-异步操作(单击慢速添加,然后多次单击添加按钮,稍后您将看到当单击慢速添加按钮时,状态已重置为闭包内的状态)

const-App=()=>{
const[counter,setCounter]=useState(0);
返回(
计数器{counter}

{ 设置计数器(计数器+1); }} > 立即添加 { setTimeout(()=>setCounter(计数器+1),1000); }} > 添加 ); };
2-在同一个闭包中多次调用update函数时

const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
          setCounter(counter + 1);
        }}
      >
        Add twice
      </button>
   
    </>
  );
}
const-App=()=>{
const[counter,setCounter]=useState(0);
返回(
计数器{counter}

{ 设置计数器(计数器+1); 设置计数器(计数器+1); }} > 加两次 ); }
使用函数允许React在内部优化许多setState调用的分辨率。对于简单的应用程序,这是不必要的。但是,对于未来可能会发展得非常庞大的应用程序来说,以这种方式启动所有setter可能是一个不错的选择。为了清楚起见,“功能更新”(functional updates,功能编程)的概念暗示了某些事情。您应该知道,在内部,react state对象实际上存储为一系列。因此,通过使用函数作为setState参数,您只需将另一个纯函数添加到记忆函数堆栈中即可。请参见例如或示例谢谢您附上工作示例。
const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
        }}
      >
        immediately add
      </button>
      <button
        onClick={() => {
          setTimeout(() => setCounter(counter + 1), 1000);
        }}
      >
        Add
      </button>
    </>
  );
};
const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
          setCounter(counter + 1);
        }}
      >
        Add twice
      </button>
   
    </>
  );
}