如何在Redux中避免Reducer硬编码初始状态并预加载数据?
解决方案:从json-server加载Redux初始状态的问题
一、先修复请求的核心错误
你的saga代码中,fetch的URL多了一个多余的冒号,这会导致请求失败:
// 错误写法 const res = await fetch(`http://localhost:3500/categories:`); // 修正后 const res = await fetch(`http://localhost:3500/categories`);
二、调整Reducer初始状态
将硬编码的分类数据移除,改为合理的空初始状态:
export const getCategoryReducer = ( state = { category: [], // 改为空数组 loading: false, err: '', }, action ) => { switch (action.type) { case LOAD_CATEGORY: return { ...state, loading: true, }; case GET_CATEGORY_SUCCESS: return { ...state, category: action.category, loading: false, }; case GET_CATEGORY_FAIL: return { ...state, err: action.message, loading: false, }; default: return state; } };
三、优化组件渲染逻辑,适配空初始状态
当前组件在category为空时执行map会报错,需先判断数组长度;同时避免直接操作DOM,改用状态控制元素显示:
import React, { useMemo, useState, useEffect } from 'react'; // 其他导入不变 const ProductConatiner = ({ category, err, loading, clickHandler }) => { const [showProgress, setShowProgress] = useState(false); useEffect(() => { setShowProgress(!loading && !err); }, [loading, err]); if (loading) { return ( <SkeletonTheme className="container"> <Skeleton color="grey" highlightColor="#AAA" className="handle skeleton" ></Skeleton> </SkeletonTheme> ); } if (err) { return ( <h1 style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', color: 'red', }} > {err} 请刷新页面 </h1> ); } function quantityHandler() { console.log('quantityHandler'); } const Images = useMemo(() => { if (!category.length) return null; return category.map((el, idx) => { return ( <LazyLoadComponent key={el.id}> <LazyLoadImage delayTime={250} delayMethod="throttle" useIntersectionObserver={true} threshold={500} effect="opacity" src={el.url} alt={el.name} /> <input key={`${el.id}-input`} className="image-input" onChange={quantityHandler} type="number" value="1" ></input> <label>kg</label> </LazyLoadComponent> ); }); }, [category]); return ( <div className="container"> <div className="progress-item" style={{ display: showProgress ? 'block' : 'none' }}></div> <button onClick={(e) => clickHandler(e.target)} className="handle left-handle" > <div className="text">‹</div> </button> <div className="slider">{Images}</div> <button onClick={(e) => clickHandler(e.target)} className="handle right-handle" > <div className="text">›</div> </button> </div> ); }; export default ProductConatiner;
四、尽早触发数据请求
React的渲染机制决定了首次渲染会使用初始状态,我们无法做到“渲染前加载完成”,但可以让请求更早触发:
方法1:在根组件中触发请求
将请求逻辑放在根组件(如App.js)的useEffect中,比子组件更早启动请求:
// App.js import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { getCategoryFetch } from './path-to-actions'; function App() { const dispatch = useDispatch(); useEffect(() => { dispatch(getCategoryFetch('Bakery')); }, [dispatch]); return ( // 应用组件树 ); }
方法2:在saga启动时自动触发请求
让saga在应用启动时自动执行一次请求:
import { call, put, takeLatest, fork } from 'redux-saga/effects'; import { LOAD_CATEGORY } from './path-to-action-types'; // 原categoryFetch和getCategory函数不变 function* initCategory() { yield put({ type: LOAD_CATEGORY, payload: 'Bakery' }); } export default function* mySagaCategory() { yield fork(initCategory); // 启动时自动执行一次 yield takeLatest(LOAD_CATEGORY, getCategory); }
内容的提问来源于stack exchange,提问作者Old-Prune6489
相关产品推荐
相关产品推荐

