React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:

setState(
  { name: "Michael" },
  () => console.log(this.state)
);

我想在状态更新后做一些事情。

我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。


当前回答

如果你想要更新之前的状态,那么你可以在hooks中这样做:

const [count, setCount] = useState(0);


setCount(previousCount => previousCount + 1);

其他回答

您需要使用useEffect钩子来实现这一点。

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

const doSomething = () => {
  setCounter(123);
}

useEffect(() => {
   console.log('Do something after counter has changed', counter);
}, [counter]);

如果你想在第一次初始渲染时忽略useEffect回调,那么相应地修改代码:

import React, { useEffect, useRef } from 'react';

const [counter, setCounter] = useState(0);
const didMount = useRef(false);

const doSomething = () => {
  setCounter(123);
}

useEffect(() => {
  // Return early, if this is the first render:
  if ( !didMount.current ) {
    return didMount.current = true;
  }
  // Paste code to be executed on subsequent renders:
  console.log('Do something after counter has changed', counter);
}, [counter]);

如果你想要更新之前的状态,那么你可以在hooks中这样做:

const [count, setCount] = useState(0);


setCount(previousCount => previousCount + 1);

UseEffect是主要的解决方案。但正如Darryl提到的,使用useEffect并将state作为第二个参数传入有一个缺陷,组件将在初始化过程中运行。如果你只想让回调函数使用更新后的状态值运行,你可以设置一个本地常量,并在setState和回调中使用它。

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

const doSomething = () => {
  const updatedNumber = 123;
  setCounter(updatedNumber);

  // now you can "do something" with updatedNumber and don't have to worry about the async nature of setState!
  console.log(updatedNumber);
}

我们可以写一个叫做useScheduleNextRenderCallback的钩子,它返回一个“schedule”函数。在我们调用setState之后,我们可以调用“schedule”函数,传递一个我们希望在下次呈现时运行的回调。

import { useCallback, useEffect, useRef } from "react";

type ScheduledCallback = () => void;
export const useScheduleNextRenderCallback = () => {
  const ref = useRef<ScheduledCallback>();

  useEffect(() => {
    if (ref.current !== undefined) {
      ref.current();
      ref.current = undefined;
    }
  });

  const schedule = useCallback((fn: ScheduledCallback) => {
    ref.current = fn;
  }, []);

  return schedule;
};

使用示例:

const App = () => {
  const scheduleNextRenderCallback = useScheduleNextRenderCallback();

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

  const onClick = useCallback(() => {
    setState(state => state + 1);
    scheduleNextRenderCallback(() => {
      console.log("next render");
    });
  }, []);

  return <button onClick={onClick}>click me to update state</button>;
};

简化的测试用例:https://stackblitz.com/edit/react-ts-rjd9jk

这个怎么样:

const [Name, setName] = useState("");
...
onClick={()=>{
setName("Michael")
setName(prevName=>{...}) //prevName is Michael?
}}