我怎样才能防止在Redux中Reducer的硬编码初始状态,而初始渲染

bksxznpy  于 2023-03-18  发布在  其他
关注(0)|答案(1)|浏览(131)

我通过reducer的初始状态获取类别状态项,但是获取redux状态的方式看起来有点混乱和硬编码,因此,我只想获取我自己创建的虚拟JSON数据,并使用json-server包提供,但是,我无法在useEffect钩子的render内部设置初始状态女巫调度redux-saga。有办法解决这个问题吗?

您可以理解代码块下面的操作的故事;

  • 减速器块;如果没有我想用空对象更改的初始分派,下面的代码块 *
export const getCategoryReducer = (
    state = {
        category: [
            {
                id: '1',
                name: 'bread',
                url: 'https://via.placeholder.com/210/00FF00?text=1',
                alt: 'bread',
            },
            {
                id: '2',
                name: 'croissant',
                url: 'https://via.placeholder.com/220/00FF00?text=2',
                alt: 'sdfalksdjflkasjdfk',
            },
            {
                id: '3',
                name: 'birthday-cake',
                url: 'https://via.placeholder.com/230/00FF00?text=3',
                alt: 'sdfalksdjflkasjdfk',
            },
        ],
        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;
    }
};

注意:initialState的项多于上述代码块

  • 我尝试了通过Redux-saga使用UseEffect Hooks的调度操作,但是在页面渲染之前它不会加载json-server bakery类别的项目;*
useEffect(() => {
        dispatch(getCategoryFetch('Bakery'));
    }, []);

这是一个生成器函数,当操作通过时触发,然后从我创建的json-server本地服务器获取数据;

import { call, put, takeLatest } from 'redux-saga/effects';

const categoryFetch = async (category) => {
    const res = await fetch(`http://localhost:3500/categories:`);

    if (!res.ok) {
        throw new Error('Something went wrong');
    }

    const data = await res.json();

    return data[`${category}`];
};

function* getCategory(action) {
    try {
        const category = yield call(categoryFetch, action.payload);
        yield put({ type: GET_CATEGORY_SUCCESS, category });
    } catch (err) {
        yield put({ type: GET_CATEGORY_FAIL, message: err.message });
    }
}

export default function* mySagaCategory() {
    yield takeLatest(LOAD_CATEGORY, getCategory);
}

在下面的代码中呈现动态类别项;

import React, { useCallback, useEffect, useMemo } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import {
    LazyLoadImage,
    LazyLoadComponent,
} from 'react-lazy-load-image-component';
import './ProductContainer.css';

const ProductConatiner = ({ category, err, loading, clickHandler }) => {
    if (loading) {
        document.querySelector('.progress-item').style.display = 'none';
        return (
            <SkeletonTheme className="container">
                <Skeleton
                    color="grey"
                    highlightColor="#AAA"
                    className="handle skeleton"
                    // duration={2.5}
                    // height="55"
                ></Skeleton>
            </SkeletonTheme>
        );
    }

    if (err.length > 0) {
        document.querySelector('.progress-item').style.display = 'none';
        return (
            <h1
                style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    color: 'red',
                }}
            >
                {err + ' reload the page'}
            </h1>
        );
    }

    useEffect(() => {
        document.querySelector('.progress-item').style.display = 'block';
    }, []);

    function quantityHandler() {
        console.log('quantityHandler');
    }

    const Images = useMemo(() => {
        return category.map((el, idx) => {
            return (
                <LazyLoadComponent>
                    <LazyLoadImage
                        delayTime={250}
                        delayMethod="throttle"
                        useIntersectionObserver={true}
                        threshold={500}
                        effect="opacity"
                        key={el.id}
                        src={el.url}
                        alt={el.name}
                    />
                    <input
                        key={idx + 'input'}
                        className="image-input"
                        onChange={quantityHandler}
                        type="number"
                        value="1"
                    ></input>
                    <label>kg</label>
                </LazyLoadComponent>
            );
        });
    }, [category]);

    return (
        <div className="container">
            <button
                onClick={(e) => clickHandler(e.target)}
                className="handle left-handle"
            >
                <div className="text">&#8249;</div>
            </button>
            <div className="slider">{Images}</div>
            {/* <div className="inputs">{quantityItems} </div> */}
            <button
                onClick={(e) => clickHandler(e.target)}
                className="handle right-handle"
            >
                <div className="text">&#8250;</div>
            </button>
        </div>
    );
};

export default ProductConatiner;
xa9qqrwz

xa9qqrwz1#

在页面呈现之前不加载它是非常正常的,即使您找到了这样做的方法(通过延迟应用程序的启动),它也不能反映当今React开发的“现实”。
正常情况下,你的组件渲染时没有它需要的数据,然后执行useEffect,然后服务器在任何时间(可能是10 ms,也可能是10 s)应答。在这期间,你的组件负责检测数据是否不存在,并渲染一个“加载”状态。
因为这种模式几乎在你做的每件事上都是现实的,所以在这种情况下,你不会通过“作弊”来学到实质性的东西,而是从一开始就学习它。
话虽如此,你在这里使用的Redux的风格已经严重过时了。现代Redux(自2019年起)不再使用switch.. case reducers或ACTION_TYPES。此外,Redux-saga不再推荐用于大多数用例。由于现代Redux只占代码的1/4左右,因此您编写的不仅是过时的代码,您还编写了大量不必要的代码。请给予this article about modern Redux,然后考虑遵循the official Redux tutorial
PS:你在document.querySelector上做的事情,使用外部元素的css样式作为“状态源”是有问题的--更新那些外部值永远不会使你的组件重新呈现。这意味着你的组件和那些外部值很容易失去同步。使用本地或全局(Redux)状态,而不是任意的元素属性。那些属性与你的应用程序生命周期不同步。

相关问题