首页 > 解决方案 > 如何避免从另一个 useEffect() 触发 useEffect()?

问题描述

我正在使用 React 实现分页。它通常运作良好,除了一个问题。

当我更改排序标准时,我想将页面重置为第一页。问题是,更改页码会再次触发数据获取。因此,每当我在第 2 页或更高页面上并更改排序标准时,都会获取两次数据。一次是因为更改标准(这会触发将页面重置为 1),然后再一次是因为页面更改为 1。有没有什么干净的方法可以避免这种冲突并使提取只发生一次?

这是我的简化代码:

import { useState, useEffect } from 'react';

export default function MyComponent() {
    const [items, setItems] = useState([]);
    const [column, setColumn] = useState();
    const [direction, setDirection] = useState();
    const [currentPage, setCurrentPage] = useState(1);
    const [perPage, setPerPage] = useState(10);

    useEffect(
        () => (async () => {
            const response = await fetch('...');
            const { items } = await response.json();

            setItems(items);
        })(),
        [column, direction, currentPage, perPage]
    );

    useEffect(
        () => setCurrentPage(1), // This triggers the useEffect() above
        [column, direction, perPage]
    );

    return (
        // Template code
    );
}

React 大师将如何做到这一点?

标签: reactjspaginationuse-effect

解决方案


您可以添加一个shouldFetch可以用于有条件地获取和避免多次调用的状态。

编辑 nostalgic-williams-b4xfo

  const [column, setColumn] = useState();
  const [direction, setDirection] = useState();
  const [currentPage, setCurrentPage] = useState(1);
  const [perPage, setPerPage] = useState(10);
  const [shouldFetch, setShouldFetch] = useState(true);

  useEffect(() => {
    (async () => {
      if (shouldFetch) {
        const response = await sleep(1000);
        console.log(response);

        // prevent fetch as we want to allow it later
        setShouldFetch(false);
      }
    })();
  }, [column, direction, currentPage, perPage, shouldFetch]);

  useEffect(() => {
    setCurrentPage(1);
    // allow fetch
    setShouldFetch(true);
  }, [column, direction, perPage]);

  const changeColumn = () => {
    setColumn("new-col");
  };
  const changeCurrentPage = () => {
    setCurrentPage(2);

    // to fetch when currentPage changes
    // this should not be added to other handlers as it is also present in the second useEffect that gets triggered when other params change
    setShouldFetch(true);
  };
  const changePerPage = () => {
    setPerPage(20);
  };
  const changeDirection = () => {
    setDirection("descending");
  };

选择:

为了避免不必要的获取并确保items使用更新的状态值获取它们,您可以删除第二个并在更新其他参数时useEffect重置。currentPage

这只会触发useEffect一次,因为 React 将同时执行两个状态更新 (setColumnsetCurrentPage)。

编辑黎明海2rdif

const sleep = (ms) => new Promise((res) => setTimeout(() => res("Hi Mom"), ms));

export default function App() {
  // const [items, setItems] = useState([]);
  const [column, setColumn] = useState();
  const [direction, setDirection] = useState();
  const [currentPage, setCurrentPage] = useState(1);
  const [perPage, setPerPage] = useState(10);

  useEffect(() => {
    (async () => {
      const response = await sleep(1000);
      console.log(response);
    })();
  }, [column, direction, currentPage, perPage]);

  // remove this effect
  // useEffect(() => setCurrentPage(1), [column, direction, perPage]);

  const changeColumn = () => {
    setColumn("new-col");
    setCurrentPage(1);
  };
  const changeCurrentPage = () => {
    setCurrentPage(2);
  };
  const changePerPage = () => {
    setPerPage(20);
    setCurrentPage(1);
  };
  const changeDirection = () => {
    setDirection("descending");
    setCurrentPage(1);
  };

  return (
    <>
      <button onClick={changeColumn}>change column</button>
      <button onClick={changeDirection}>change direction</button>
      <button onClick={changeCurrentPage}>change page</button>
      <button onClick={changePerPage}>change perPage</button>
    </>
  );
}

推荐阅读