web-dev-qa-db-fra.com

Actions asynchrones dans Redux

J'ai un React App, je dois passer un appel ajax (pour apprendre) à un service en ligne (asynchrone) avec Redux.

Ceci est mon magasin:

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


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

Ce sont les actions:

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))
    )
}

Et voici le réducteur:

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

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

Je ne comprends pas ce que je fais mal. L'action est appelée parfaitement à partir du composant. Mais alors je reçois cette erreur:

Erreur: Les actions doivent être des objets simples. Utilisez un middleware personnalisé pour les actions asynchrones.

Je suppose que j'utilise mal le middleware react-thunk. Qu'est-ce que je fais mal?

EDIT

Maintenant, l'action appelle le réducteur, mais le réducteur, après avoir changé d'état, ne réexécute pas la méthode de rendu.

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

        return state.dueDates = action.dueDates;
32
Pablo

Je pense que vous devriez utiliser la fonction compose, donc c'est comme

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

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

Thunk permet à un créateur d’action de renvoyer une fonction au lieu d’un objet simple. Vous l’utilisez donc comme

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

Vous retourniez un objet Promise, c'était une partie du problème. Une autre partie est que redux-thunk n'a pas été correctement appliqué. Je parie que compose devrait résoudre le problème.

29
Fleischpflanzerl

La réponse acceptée est soit dépassée, soit erronée, soit trop compliquée. Voici la documentation sur le sujet de composition:

http://redux.js.org/docs/api/compose.html

afin que nous puissions le faire comme ceci à la place:

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))
);
17
Alexander Mills

Je crois qu’il est possible d’avoir une solution opérationnelle sans utiliser aussi la fonction compose. Basé sur la documentation du repo GitHub pour redux-thunk

La solution fonctionne pour 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)
  );
}
1
Kevin Farrugia