Redux中的异步操作

xkftehaa  于 2022-12-23  发布在  其他
关注(0)|答案(4)|浏览(149)

我有一个React的应用程序,我需要一个ajax调用(为了学习)与Redux在线服务(异步)。
这是我的店:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import duedates from './reducers/duedates'

export default applyMiddleware(thunk)(createStore)(duedates);

以下是操作:

import rest from '../Utils/rest';

export function getDueDatesOptimistic(dueDates){
    console.log("FINISH FETCH");
    console.log(dueDates);
    return {
        type: 'getDueDate',
        dueDates
    }
}

export function waiting() {
    console.log("IN WAIT");
    return {
        type: 'waiting'
    }
}

function fetchDueDates() {
    console.log("IN FETCH");
    return rest({method: 'GET', path: '/api/dueDates'});
}

export function getDueDates(dispatch) {
    console.log("IN ACTION");
    return fetchDueDates().done(
        dueDates => dispatch(getDueDatesOptimistic(dueDates.entity._embedded.dueDates))
    )
}

这是减速器

export default (state = {}, action) => {
  switch(action.type) {
    case 'getDueDate':
        console.log("IN REDUCER")

        return state.dueDates = action.dueDates;
    default:
        return state
  }
}

我不知道我做错了什么。这个动作从组件中被完美地调用了。但是我得到了这个错误:
错误:操作必须是普通对象。请为异步操作使用自定义中间件。
我想我用错了react-thunk中间件,我做错了什么?

    • 编辑**

现在,该操作正在调用reducer,但reducer在更改状态后不会重新运行render方法

case 'getDueDate':
        console.log("IN REDUCER")

        return state.dueDates = action.dueDates;
uqjltbpv

uqjltbpv1#

我认为你应该使用compose函数,就像

import {
  createStore,
  applyMiddleware,
  compose
} from 'redux';
import thunk from 'redux-thunk';
import duedates from './reducers/duedates'

export default compose(applyMiddleware(thunk))(createStore)(duedates);

Thunk允许操作创建者返回函数而不是普通对象,因此您可以像这样使用它

export function getDueDates() {
  return dispatch => {
    console.log("IN ACTION");
    fetchDueDates().done(
      dueDates => dispatch(getDueDatesOptimistic(dueDates.entity._embedded.dueDates))
    )
  };
}

你返回了一个Promise对象,这是问题的一部分。另一部分是redux-thunk没有被正确应用。我打赌compose应该可以解决这个问题。

vxqlmq5t

vxqlmq5t2#

公认的答案要么是过时的,要么是错误的,要么是过于复杂的。以下是关于写作主题的文档:
http://redux.js.org/docs/api/compose.html
所以我们可以这样做:

import {createStore, combineReducers, compose, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';

const reducer = combineReducers({
    user: userReducer,
    items: itemsReducer
});

// here is our redux-store
const store = createStore(reducer,
    compose(applyMiddleware(thunk))
);
cnh2zyt3

cnh2zyt33#

我相信在不使用compose函数的情况下也可以有一个可行的解决方案。基于GitHub repo for redux-thunk的文档

  • 解决方案适用于redux-thunk: ^2.0.0*
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import duedates from './reducers/duedates'

export function configureStore(initialState = {}) {
  return createStore(
    duedates,
    initialState,
    applyMiddleware(thunk)
  );
}
628mspwn

628mspwn4#

我看到了不同语法的多个答案,我将提出一个解决方案,而不必手动应用中间件,也不必单独安装redux-thunk
唯一的redux依赖项:@reduxjs/toolkit: ^1.8.6
src/redux/store.js

import { configureStore } from "@reduxjs/toolkit";
import category from './features/category.feature';

const store = configureStore({
    reducer: {
        category
    }
});

export default store;

src/redux/features/category.feature.js

import { createSlice } from "@reduxjs/toolkit";
import { XHR_STATUS } from "../../misc/enums";
import axios from 'axios';
import { BASE_URL } from "../../misc/constants/xhr";

const initialState = {
    data: [],
    status: XHR_STATUS.NEUTRAL,
    errorMessage: ''
};

let slice = createSlice({
    name: 'category',
    initialState,
    reducers: {
        setStatus: (state, actions) => {
            state.status = actions.payload;
        },
        setData: (state, action) => {
            state.data = action.payload;
        }
    }
});

export const { setStatus, setData } = slice.actions;

export const fetchCategories = () => {
    return async (dispatch) => {
        dispatch(setStatus(XHR_STATUS.LOADING));
        const response = await axios.get(`${BASE_URL}categories`);
        const { data } = response;
        dispatch(setData(data));
        dispatch(setStatus(XHR_STATUS.SUCCESS));
    }
}

export default slice.reducer;

src/components/Categories/index.js

import { XHR_STATUS } from '../../misc/enums';
import { ListItem, List } from '@mui/material';
import CategoryBox from '../CategoryBox'; // This is my custom component to render a single Category
function Categories (props) {
    const { category } = props;
    switch(category.status) {
        case XHR_STATUS.NEUTRAL:
            return (
                'Waitng...'
            );
        case XHR_STATUS.LOADING:
            return (
                'Loading...'
            );
        case XHR_STATUS.SUCCESS:
            return (
                <List style={{ padding: '20px 0 20px 0', display: 'inline-flex', flexDirection: 'row', overflowX: 'scroll', width: '100%' }}>
                {category.data.map((c, i) => (  
                    <ListItem key={i}>
                        <CategoryBox category={c} />
                    </ListItem>
                ))}
                </List> 
            );
        case XHR_STATUS.ERROR:
            return (
                'Error...'
            );
    }
}

相关问题