在Saga中派发动作后,组件无法获取过滤数据问题排查
Redux获取filteredCourses数据失败排查及修复方案
一、Component.js中的核心问题
1. 未定义变量直接引用
原代码直接使用courses.isLoading,但courses变量从未定义,会抛出ReferenceError。需先通过useSelector获取filteredCourses状态:
// 修复前 if (categories.isLoading || courses.isLoading) { ... } // 修复后 const filteredCourses = useSelector(state => state.filteredCourses); if (categories.isLoading || filteredCourses.isLoading) { ... }
2. 无限循环派发Action
直接在组件函数体中调用dispatch(apiRequestFilteredCourses(query)),会导致组件每次渲染都派发Action,触发状态更新后再次渲染,形成无限循环。必须用useEffect包裹并添加依赖控制执行时机:
// 修复前 const query = { category_id: 1 }; dispatch(apiRequestFilteredCourses(query)); // 修复后 import React, { useEffect } from 'react'; // 补充useEffect导入 const Courses = () => { const categories = useSelector(state => state.categories); const filteredCourses = useSelector(state => state.filteredCourses); const dispatch = useDispatch(); useEffect(() => { // 仅当categories加载完成后再请求过滤课程 if (!categories.isLoading && categories.isLoaded) { const query = { category_id: 1 }; dispatch(apiRequestFilteredCourses(query)); } }, [categories, dispatch]); // 添加依赖项 }
二、Reducer与useSelector匹配问题
filteredCoursesReducer的状态结构是包含filteredCourses数组、isLoading、isLoaded的对象,通过useSelector获取数据时需明确取到数组:
// 错误:直接取整个状态对象 const filteredCourses = useSelector(state => state.filteredCourses); // 正确:取对象中的filteredCourses数组 const { filteredCourses: courseList, isLoading, isLoaded } = useSelector(state => state.filteredCourses); // 或分开取 const courseList = useSelector(state => state.filteredCourses.filteredCourses); const isCourseLoading = useSelector(state => state.filteredCourses.isLoading);
三、Saga中的潜在问题
filteredCoursesSagas最后一行yield put(apiRequestFilteredCourses());会在Saga启动时自动派发空参数请求,导致不必要的API调用,建议移除:
// 修复前 export default function* filteredCoursesSagas() { yield takeEvery(API_REQUEST_FILTERED_COURSES, filterCourses); yield put(apiRequestFilteredCourses()); // 移除该行 }
四、Api.js的错误处理隐患
当API请求失败时,catch块返回Error对象,Saga中解构data和status会报错,需先判断返回值是否为Error:
// Saga中修复 function* filterCourses(action) { const query = new URLSearchParams(action.payload).toString(); try { const response = yield Api.get(`courses?${query}`, false); // 先判断是否为Error if (response instanceof Error) { console.log('API请求失败:', response); return; } const { data, status } = response; if (status === 200) { yield put(apiReceiveFilteredCourses(data.data)); } else { console.log(`请求失败,状态码: ${status}`); } } catch (e) { console.log('FROM COURSES', e); } }
五、完整修复后的Component.js示例
import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { apiRequestFilteredCourses } from '../../../actions'; const Courses = () => { const categories = useSelector(state => state.categories); const { filteredCourses: courseList, isLoading: coursesLoading } = useSelector(state => state.filteredCourses); const dispatch = useDispatch(); // 加载状态判断 if (categories.isLoading || coursesLoading) { return (<h1>Loading</h1>); } useEffect(() => { // 确保categories已加载完成再请求 if (categories.isLoaded) { const query = { category_id: 1 }; dispatch(apiRequestFilteredCourses(query)); } }, [categories, dispatch]); // 渲染课程列表 return ( <div> {courseList.map(course => ( <div key={course.id}>{course.name}</div> ))} </div> ); }; export default Courses;
内容的提问来源于stack exchange,提问作者Moe
相关产品推荐
相关产品推荐

