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

如何在useEffect中实现清理函数优化Context的API数据获取

解决切换类别时旧产品数据残留的问题

核心问题分析

你的filter_products是全局上下文状态,切换类别时新API请求还未返回,组件会先渲染之前的旧数据;而且原清理逻辑仅标记inView,既没真正清空状态,也没处理API请求的竞态问题——旧请求可能晚于新请求完成,导致新数据被覆盖。

具体修复步骤

1. 给FilterReducer添加清空数据的动作

在你的reducer函数里新增CLEAR_FILTER_PRODUCTS类型的处理:

const reducer = (state, action) => {
  switch(action.type) {
    // 保留现有其他case逻辑
    case "CLEAR_FILTER_PRODUCTS":
      return {
        ...state,
        filter_products: [],
        // 可选:如果有loading/error状态,也可一并重置
        // isLoading: false,
        // error: ""
      };
    default:
      return state;
  }
};

2. 在FilterProvider中添加清空数据的方法

修改FilterProvider,新增clearFilterProducts方法并传入上下文:

const FilterProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { products } = useAppContext();

  const getFilterProducts = async (url) => {
    dispatch({ type: "FILTERS_LOADING" });
    try {
      const res = await fetch(url);
      const data = await res.json();
      if (!res.ok) {
        var error = new Error("Error" + res.status + res.statusText);
        throw error;
      }
      dispatch({ type: "LOAD_FILTER_PRODUCTS", payload: data.products });
    } catch (err) {
      dispatch({ type: "FILTERS_ERROR", payload: err.message });
    }
  };

  // 新增清空数据的方法
  const clearFilterProducts = () => {
    dispatch({ type: "CLEAR_FILTER_PRODUCTS" });
  };

  return (
    <FilterContext.Provider value={{ ...state, getFilterProducts, clearFilterProducts }}>
      {children}
    </FilterContext.Provider>
  );
};

3. 在ProductsList组件中卸载时清空数据

修改ProductsList的useEffect,在清理函数里调用clearFilterProducts:

const ProductsList = () => {
  const { cate } = useParams();
  const { getFilterProducts, filter_products, clearFilterProducts } = useFilterContext();

  useEffect(() => {
    getFilterProducts(`${API}/category/${cate}`);

    // 组件卸载时清空旧数据
    return () => {
      clearFilterProducts();
    };
  }, [cate, getFilterProducts, clearFilterProducts]);

  return (
    <div className="mx-2 mt-2 mb-16 md:mb-0 grid grid-cols-1 md:grid-cols-12">
      <div className="h-9 w-full md:col-span-2">
        <FilterSection />
      </div>
      <div className="md:col-span-10">
        <ProductListDetails products={filter_products} />
      </div>
    </div>
  );
};

4. 可选:处理API请求竞态问题

如果快速切换类别时出现旧请求覆盖新数据的情况,可用AbortController取消旧请求:

// 修改FilterProvider中的getFilterProducts方法
const getFilterProducts = async (url, signal) => {
  dispatch({ type: "FILTERS_LOADING" });
  try {
    const res = await fetch(url, { signal }); // 传入取消信号
    const data = await res.json();
    if (!res.ok) {
      var error = new Error("Error" + res.status + res.statusText);
      throw error;
    }
    dispatch({ type: "LOAD_FILTER_PRODUCTS", payload: data.products });
  } catch (err) {
    // 忽略请求被取消的错误
    if (err.name !== "AbortError") {
      dispatch({ type: "FILTERS_ERROR", payload: err.message });
    }
  }
};

然后更新ProductsList的useEffect:

useEffect(() => {
  const controller = new AbortController();
  const { signal } = controller;

  getFilterProducts(`${API}/category/${cate}`, signal);

  return () => {
    controller.abort(); // 取消当前未完成的请求
    clearFilterProducts();
  };
}, [cate, getFilterProducts, clearFilterProducts]);

修改完成后,切换类别时组件卸载会清空旧数据,再次进入时会先显示空状态(可配合loading状态添加加载提示),等API请求返回后展示当前类别的数据,彻底解决旧数据残留的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:50:25