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

React+Redux Toolkit+Redux-saga仅渲染最后一次moviedb API返回值问题

问题根因

1. 状态未隔离导致数据被覆盖

你当前的movieSlice只存储了单一的影片数据集,每次接口返回结果都会直接覆盖全局movie状态的results字段,所有Row组件共享同一个数据源,最终自然只会显示最后一次接口返回的内容。

2. 全量订阅导致重复渲染

所有Row组件都通过useSelector监听了整个state.movie,只要movie状态发生一次更新,所有订阅该状态的Row都会触发重渲染。如果有N个Row组件,就会发起N次接口请求,每次请求返回更新状态都会让N个Row各打印一次日志,最终就会出现N*N次重复打印的情况。


修复方案

第一步:改造movieSlice,按分类隔离存储数据

把state从单一对象改为键值对结构,用每个影片分类的唯一标识作为key,对应存储该分类的影片数据,避免不同分类的数据互相覆盖:

// movieSlice.js
import { createSlice } from "@reduxjs/toolkit";

const movieSlice = createSlice({
  name: "movie",
  initialState: {}, // 初始为对象,按分类key存储数据
  reducers: {
    getMovie() {},
    setMovie(state, action) {
      const { categoryKey, data } = action.payload;
      // 只更新对应分类的数据
      state[categoryKey] = data;
    },
  },
});

export const { getMovie, setMovie } = movieSlice.actions;
export default movieSlice.reducer;

第二步:修改saga逻辑,透传分类标识

saga拿到接口返回结果后,把分类标识和对应数据一起提交到reducer:

// sagas/handlers/movie.js
import { call, put } from "redux-saga/effects";
import { requestGetMovie } from "../requests/movies";
import { setMovie } from "../../ducks/movieSlice";

export function* handleGetMovie(action) {
  try {
    const { fetchLink, categoryKey } = action.payload;
    const response = yield call(requestGetMovie, { fetchLink });
    const { data } = response;
    // 携带分类标识提交数据
    yield put(setMovie({ categoryKey, data }));
  } catch (error) {
    console.log(error);
  }
}

第三步:改造Row组件,仅订阅自身对应数据

dispatch请求时携带当前分类的唯一标识,取数时也只拉取当前分类对应的数据,避免被其他分类的状态更新触发多余重渲染:

// Row.js
import React, { useEffect } from "react";
import styled from "styled-components";
import { useDispatch, useSelector, shallowEqual } from "react-redux";
import { getMovie } from "../redux/ducks/movieSlice";

function Row({ title, fetchUrl }) {
  const dispatch = useDispatch();
  // 用fetchUrl作为分类的唯一标识,也可以用不重复的title代替
  const categoryKey = fetchUrl;

  useEffect(() => {
    dispatch(
      getMovie({
        fetchLink: fetchUrl,
        categoryKey: categoryKey
      })
    );
  }, [dispatch, fetchUrl, categoryKey]);

  // 仅订阅当前分类对应的影片数据,加shallowEqual减少不必要的重渲染
  const movie = useSelector((state) => {
    return state.movie[categoryKey]?.results;
  }, shallowEqual);

  return (
    <RowContainer>
      {title}
      <CardsContainer>{movie && movie[0]?.name}</CardsContainer>
    </RowContainer>
  );
}

export default Row;

const RowContainer = styled.div`
  color: white;
`;

const CardsContainer = styled.div`
  color: white;
`;

修改完成后不同分类的影片数据会独立存储互不干扰,每个Row只会在自身对应数据更新时重渲染,即可解决数据覆盖和重复打印的问题。


内容的提问来源于stack exchange,提问作者Sarthak-bleepboop

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 12:39:01