You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复react-hooks/exhaustive-deps错误并优化分页实现?

问题

遇到了react-hooks/exhaustive-deps的lint错误警告,代码如下:

const fetchData = async pageNumber => {
    if (pageNumber > totalPages) {
      return;
    }

    try {
      setIsLoading(true);
      // ... call api
      const content = response.data.content;
      if (pageNumber === 1) {
        setTotalPages(response.data.totalPages);
        setActivityData(content);
      } else {
        setActivityData([...activityData, ...content]);
      }
      setCurrPage(currPage + 1);
    } catch (e) {
      console.log(e);
    } finally {
      // ...
    }
  };

useEffect(() => {
    fetchData(currPage);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [currPage]);

useEffect(() => {
  setCurrPage(1);
  setActivityData([]);
  setTotalPages(1);
}, [activityStatus]);

这段代码用于分页展示activityData。如果把fetchData加入useEffect依赖,会触发函数重渲染相关错误;尝试过把fetchData放入useEffect但无法实现,现咨询:

  1. 当前的useEffect用法存在什么问题?
  2. 有没有更好的分页管理与展示方式?
回答

1. 当前useEffect用法的问题

  • 用eslint-disable跳过依赖检查本质是回避核心问题:fetchData依赖组件内部的activityData、currPage、totalPages等state,每次组件渲染时fetchData都会被重新创建。如果把它加入useEffect依赖,会导致useEffect在每次渲染时都触发,进而调用fetchData更新state,最终引发无限循环。
  • fetchData直接使用state的当前值存在闭包陷阱:比如当activityData更新后,fetchData里捕获的还是旧的activityData值,拼接数据时会出现错误;同理currPage的更新也可能基于旧值,导致页码计算偏差。

2. 更好的分页管理与展示方式

方案一:useCallback包裹fetchData+ 函数式更新state

用useCallback缓存fetchData,避免每次渲染都重新创建;同时用函数式更新state,获取最新的state值,解决闭包问题:

const fetchData = useCallback(async (pageNumber) => {
  if (pageNumber > totalPages) return;

  try {
    setIsLoading(true);
    // ... call api
    const content = response.data.content;
    if (pageNumber === 1) {
      setTotalPages(response.data.totalPages);
      setActivityData(content);
    } else {
      // 函数式更新,获取最新的activityData
      setActivityData(prev => [...prev, ...content]);
    }
    // 函数式更新currPage
    setCurrPage(prev => prev + 1);
  } catch (e) {
    console.log(e);
  } finally {
    setIsLoading(false);
  }
}, [totalPages]); // 只依赖totalPages,其他state用函数式更新获取

useEffect(() => {
  fetchData(currPage);
}, [currPage, fetchData]); // 现在可以安全加入fetchData依赖

方案二:将fetchData逻辑移入useEffect内部

如果不需要复用fetchData,直接把逻辑放进useEffect,完全避免函数依赖问题:

useEffect(() => {
  const fetchData = async () => {
    if (currPage > totalPages) return;

    try {
      setIsLoading(true);
      // ... call api
      const content = response.data.content;
      if (currPage === 1) {
        setTotalPages(response.data.totalPages);
        setActivityData(content);
      } else {
        setActivityData(prev => [...prev, ...content]);
      }
      setCurrPage(prev => prev + 1);
    } catch (e) {
      console.log(e);
    } finally {
      setIsLoading(false);
    }
  };

  fetchData();
}, [currPage, totalPages]); // 只依赖必要的state

方案三:自定义Hook封装分页逻辑

把分页相关的state和逻辑封装成自定义Hook,提升复用性和代码整洁度:

const usePagedActivity = (activityStatus) => {
  const [activityData, setActivityData] = useState([]);
  const [currPage, setCurrPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);
  const [isLoading, setIsLoading] = useState(false);

  const fetchData = useCallback(async (pageNumber) => {
    if (pageNumber > totalPages) return;
    setIsLoading(true);
    try {
      // ... 根据activityStatus调用api
      const response = await api.getActivity({ page: pageNumber, status: activityStatus });
      const content = response.data.content;
      if (pageNumber === 1) {
        setTotalPages(response.data.totalPages);
        setActivityData(content);
      } else {
        setActivityData(prev => [...prev, ...content]);
      }
      setCurrPage(prev => prev + 1);
    } catch (e) {
      console.log(e);
    } finally {
      setIsLoading(false);
    }
  }, [activityStatus, totalPages]);

  // 切换状态时重置分页
  useEffect(() => {
    setCurrPage(1);
    setActivityData([]);
    setTotalPages(1);
  }, [activityStatus]);

  // 页码变化时请求数据
  useEffect(() => {
    if (currPage === 1 || currPage <= totalPages) {
      fetchData(currPage);
    }
  }, [currPage, fetchData]);

  return { activityData, currPage, totalPages, isLoading };
};

// 在组件中使用
const { activityData, isLoading } = usePagedActivity(activityStatus);

内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:45:01