解决api请求返回顺序紊乱的问题react项目

问题描述:

点击A、B、C,如果操作过快,会出现虽然点击了C,但是上面显示的是B的信息。


image.png

解决方案

每轮渲染的 Effect 都有其独立的 ignore 变量。最初,ignore 变量被设置为 false。但如果一个 Effect 被清理(例如,当你选择不同的人时),它的 ignore 变量会变为 true。因此,请求完成的顺序已经不再重要。只有最后选中的 Effect 的 ignore 变量会是 false,因此它将会调用 setData(result)。而之前的 Effect 已经被清理,所以 if (!ignore) 的检查会阻止它们调用 setData:

const DELAY_MIL_SEC = [2000, 3000, 1000];
const ID_LABEL = ['A', 'B', 'C'];
export default function Demo() {
const [activeIndex, setActiveIndex] = useState<number>(0);
const [data, setData] = useState({ id: '', timestamp: '', back: '' });


// 在这里添加状态量,只会显示最先点击的结果,最后点击的结果不会显示。
// 理想的情况是显示最后点击的结果,而不是最先点击的结果。
const onClick = (id: number) => {
  if (refReq.current) return; // 信号量存在
  refReq.current = true;
  api.user
    .delayFn({ id, delay: DELAY_MIL_SEC[id] })
    .then((response) => {
      refReq.current = false;
      setData({ ...response });
    })
    .catch((err) => {
      console.error('err', err);
    });
};

useEffect(() => {
  let ignore = false;
  setData({ id: '', timestamp: '', back: '' });
  api.user
    .delayFn({ id: activeIndex, delay: DELAY_MIL_SEC[activeIndex] })
    .then((response) => {
      if (!ignore) {
        setData({ ...response });
      }
    })
    .catch((err) => {
      console.error('err', err);
    });

  return () => {
    ignore = true;
  };
}, [activeIndex]);

return (
  <div className={styles.App}>
    <header className={styles.AppHeader}>
      <h2>解决api请求返回顺序紊乱的问题</h2>
      <div>
        {data?.id.toString() && (
          <p>
            <span>{ID_LABEL[data.id]}</span>
            &nbsp;&nbsp;
            <span>{data.timestamp}</span>
            &nbsp;&nbsp;
            <span>{data.back}</span>
          </p>
        )}
        {ID_LABEL.map((label: string, index: number) => (
          // eslint-disable-next-line react/button-has-type
          <button
            key={label}
            onClick={() => {
              // onClick(index);
              setActiveIndex(index);
            }}
          >
            {`${ID_LABEL[index]}-${DELAY_MIL_SEC[index].toString().substring(0, 1)}sec`}
          </button>
        ))}
      </div>

      <div style={{ height: '600px' }}> &nbsp;</div>
    </header>
  </div>
);
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容