reactjs - 如何避免从另一个 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 大师将如何做到这一点?
解决方案
您可以添加一个shouldFetch
可以用于有条件地获取和避免多次调用的状态。
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 将同时执行两个状态更新 (setColumn
和setCurrentPage
)。
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>
</>
);
}
推荐阅读
- jenkins - 用于微服务系统的 Jenkins CI/CD 设置
- sql - 仅在案例语句中添加年份得到无效数字错误 - ORA-01722
- sql - 为什么我的 UPDATE 语句需要很长时间才能只影响 242 行?
- angular - 如何将“mat-toolbar”放在“mat-sidenav”Angular Material 5 的顶部
- web-services - 从 ABAP 激活代理服务使用者
- python - python导入无法从一个模块到另一个模块
- javascript - 从对象 javascript es6 中获取值
- json - jq合并json数组元素
- css - 更改组件的顺序不会产生预期的结果
- firebase - 当应用使用电话验证进行身份验证时,使用 Google Cloud Functions 发送欢迎电子邮件