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

如何在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">&#8249;</div>
            </button>
            <div className="slider">{Images}</div>
            <button
                onClick={(e) => clickHandler(e.target)}
                className="handle right-handle"
            >
                <div className="text">&#8250;</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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:30:02