无法理解 Counter 示例中的 React 陈旧状态

Trouble understanding React stale state in Counter example

我确定我的问题是关于 useCallback 和 setter 方法,我在这里 setSpeakersuseState 返回,但我不明白为什么我的例子,如所列here 和 codesandbox 中的状态没有正确递增。旧状态不断返回,而不是新的递增状态。当我将一个函数传递给 setSpeakers 而不仅仅是一个新状态时,我的示例有效(您可以在非工作代码下方看到标记为 THIS CODE WORKS 的注释掉的代码。

我知道其他人已经写过这方面的文章,我已经阅读了那些文章,但仍然不明白。

沙盒:https://codesandbox.io/s/elated-lichterman-7rejs?file=/pages/index.js

import React, { useState, memo, useCallback } from "react";

//const Speaker = React.memo(({ imageSrc, counter, setCounter }) => {
const Speaker = ({ speaker, speakerClick }) => {
  console.log(speaker.id);
  return (
    <div>
      <span
        onClick={() => {
          speakerClick(speaker.id);
        }}
        src={`speakerimages/Speaker-${speaker.id}.jpg`}
        width={100}
      >
        {speaker.id} {speaker.name}
      </span>
      &nbsp;&nbsp;
      <span className="fa fa-star ">&nbsp;&nbsp;{speaker.clickCount}</span>
      &nbsp;
    </div>
  );
};

function SpeakerList({ speakers, setSpeakers }) {
  return (
    <div>
      {speakers.map((speaker) => {
        return (
          <Speaker
            speaker={speaker}
            speakerClick={useCallback((id) => {


              // THIS CODE FAILS BECAUSE OF STALE STATE BUT I DON'T GET WHY
              const speakersNew = speakers.map((speaker) => {
                return speaker.id === id
                  ? { ...speaker, clickCount: speaker.clickCount + 1 }
                  : speaker;
              });
              setSpeakers(speakersNew);

              // THIS CODE WORKS
              // setSpeakers(function(speakers) {
              //   const speakersNew = speakers.map((speaker) => {
              //     return speaker.id === id
              //         ? { ...speaker, clickCount: speaker.clickCount + 1 }
              //         : speaker;
              //   });
              //   return speakersNew;
              // });



            }, [])}
            key={speaker.id}
          />
        );
      })}
    </div>
  );
}

//
const App = () => {
  const speakersArray = [
    { id: 1124, name: "aaa", clickCount: 0 },
    { id: 1530, name: "bbb", clickCount: 0 },
    { id: 10803, name: "ccc", clickCount: 0 }
  ];

  const [speakers, setSpeakers] = useState(speakersArray);

  return (
    <div>
      <h1>Speaker List</h1>
      <SpeakerList speakers={speakers} setSpeakers={setSpeakers}></SpeakerList>
    </div>
  );
};
export default App;

那是因为设置状态是异步工作的。在第一个不是 运行 的代码中,您设置状态并尝试立即显示它不会工作,因为在设置状态时存在延迟。第二个之所以有效,是因为您将回调传递给设置状态,这基本上意味着设置状态并在您处于状态时执行此操作。而第一个意味着设置状态然后再执行此操作。那不是你想要的。这是一个松散的类比,但看看 set state 是如何以及为什么是 aync 的,你会有一个更好的主意。干杯。