web-dev-qa-db-fra.com

Impossible d'accéder à action.payLoad.data à partir de la promesse redux

Je travaille sur une application météo en utilisant Redux promise, et j'ai du mal à récupérer action.payLoad.data.

actions/index.js

import axios from 'axios';

const API_KEY = 'xxxxxxxxx';
const ROOT_URL = `http://api.openweathermap.org/data/2.5/forecast?appid=${API_KEY}`;

export const FETCH_WEATHER = 'FETCH_WEATHER';

export function fetchWeather(city) {
  const url = `${ROOT_URL}&q=${city},us`;
  const request = axios.get(url);

  //console.log("request:", request);

  return {
    type: FETCH_WEATHER,
    payLoad: request
  };
}

reducers/reducer_weather.js

import  { FETCH_WEATHER } from '../actions/index';

export default function(state = [], action) {
  if (action.type === FETCH_WEATHER) {
    console.log('Action.payLoad.data received:', action.payLoad.data);
    console.log('Action received:', action);
  }

  switch (action.type) {
    case FETCH_WEATHER:
      return [ action.payLoad.data, ...state ]; // return new instance of state array
  }
  return state;
}

Peu importe comment j'ai essayé, toute combinaison autour de action.payload.data renvoie undefined. Comment accéder à sa valeur?

 screenshot

12
C. L.

Edit: Je viens de voir le commentaire où vous dites que vous utilisez redux-promise. Vous devez utiliser payload dans l'action de retour et non payLoad. Donc, votre fonction ressemblerait à ceci:

function fetchWeatherPromise (city) {
  const url = `${ROOT_URL}&q=${city},us`;
  return {
      type: 'FETCH_WEATHER',
      payload: new Promise((resolve, reject) => {
          axios.get(url).then(response => resolve(response.data))
      })
    } 
};

Et votre réducteur:

switch (action.type) {
    case 'FETCH_WEATHER_PENDING':
        ...

    case 'FETCH_WEATHER_FULFILLED':
        return [action.payload, ...state];

    default:
        return state;
};

Comme cette très bonne explication sur ce post de reddit dit:

Premièrement, quelques locaux (en redux):

  • À la fin du cycle de vie de redux, un nouveau magasin est renvoyé par un réducteur.
  • Le nouveau magasin renvoyé est le produit final de l'application des actions au magasin précédent (à l'aide de dispatch ()!).
  • Les actions doivent être de nature SYNCHRONE. Selon moi, une action doit être un objet simple avec des données simples.

Donc, si nous suivons cette ligne de pensée, nous pouvons considérer les actions comme les informations nécessaires à un réducteur pour transformer le magasin actuel en un nouveau magasin (nouvel état).

Je pense que, jusqu'à présent, vous avez compris. Alors, comment gérez-vous les requêtes api/xhr qui sont intrinsèquement asynchrones? Vous ne voulez pas mélanger les fonctions asynchrones avec des objets synchrones (actions), alors comment est-il possible d'utiliser des appels api?

C'est là qu'interviennent les créateurs d'action.

Un créateur d'action est simplement une fonction qui renvoie une action. Notez que cela ne signifie PAS qu'un créateur d'action doit envoyer l'action qu'il renvoie. Il ne fait que renvoyer cet objet simple synchrone que nous avons défini comme une action.

Sachant cela, nous pouvons spéculer: "Hmm, eh bien, si c'est juste une fonction qui retourne un objet, et si ce n'est pas nécessairement l'envoi d'actions, les créateurs d'actions peuvent-ils être asynchrones?"

La réponse à cette question est oui!

Ce que le créateur d'action fait est:

  • Il passe un appel API asynchrone à l'aide d'une promesse.
  • Il crée un objet avec la réponse renvoyée (il peut s'agir de données réelles, vous devez donc résoudre votre promesse!).
  • Il envoie une action de synchronisation au magasin avec cet objet.

Le middleware de promesse élimine le besoin d'écrire myPromise.then()... (résoudre votre promesse) chaque fois que vous souhaitez effectuer une action asynchrone. Au lieu de résoudre les promesses tout le temps, vous lui donnez simplement les informations nécessaires à la création de l'appel API et le middleware se charge du reste.


Ancien: Vous devez remodeler votre fonction et ajouter un Middleware pour traiter les créateurs d’actions asynchrones. De plus, axios.get() renvoie un promise et vous devez envoyer une action de synchronisation dans then pour que votre réducteur ait accès aux données extraites. Voici un exemple de ce à quoi votre créateur d’action devrait ressembler en utilisant redux-thunk .

function fetchWeather(city) {
return (dispatch) => {
    const url = `${ROOT_URL}&q=${city},us`;
    return axios.get(url)
        .then(res => res.data)
        .then(data => {
            dispatch({
                type: FETCH_WEATHER,
                payLoad: data
            });
        }) 
     }
}

N'oubliez pas d'ajouter applyMiddleware(thunkMiddleware) à votre magasin.

5
Tiago Alves

Vérifiez votre index.js, assurez-vous que ReduxPromise est câblé dans l'appel applyMiddleWare (), comme ceci

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';

import App from './components/app';
import reducers from './reducers';
import ReduxPromise from 'redux-promise';

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>
  , document.querySelector('.container'));

1
Michael

Je pense que vous manquez de configurer votre redux-promesse en tant que middleware. Vous devriez simplement essayer d’ajouter redux-promise comme middleware dans la configuration de votre magasin. voir ci-dessous:

 import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
 import thunk from 'redux-thunk';
 import { routerReducer, routerMiddleware } from 'react-router-redux';
 import * as Counter from './Counter';
 import * as WeatherForecasts from './WeatherForecasts';
 import BooksReducer from '../reducers/reducer_books';
 import ActiveBook from '../reducers/reducer_active_book';
 import weatherReducer from '../reducers/weather';
 import Promise from 'redux-promise';


 export default function configureStore(history, initialState) 
 {
    const reducers = 
    {
        counter: Counter.reducer,
        weatherForecasts: WeatherForecasts.reducer,
        books: BooksReducer,
        activeBook: ActiveBook,
        weather: weatherReducer
    };

const middleware = [
    thunk,
    routerMiddleware(history),
    Promise
];

// In development, use the browser's Redux dev tools extension if installed
const enhancers = [];
const isDevelopment = process.env.NODE_ENV === 'development';
if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) {
    enhancers.Push(window.devToolsExtension());
}

const rootReducer = combineReducers({
    ...reducers,
    routing: routerReducer
});

return createStore(
    rootReducer,
    initialState,
    compose(applyMiddleware(...middleware), ...enhancers)
);

}

1
Praveen

dans index.js principal 

const createStoreWithMiddleware = applyMiddleware(promise)(createStore);

dans actions/index.js

export function fetchWeather(city) {
  const url = `${ROOT_URL}&q=${city},us`;
  const request = axios.get(url);
  return {
    type: FETCH_WEATHER,
    payLoad: request
  };
}

dans les réducteurs/réducer_weather.js

import  { FETCH_WEATHER } from '../actions/index';

export default function(state = [], action) {
  switch (action.type) {
    case FETCH_WEATHER:
      return [ action.payLoad.data, ...state ]; 
  }
  return state;
}

Fonctionne bien

0
Sergey Lokhmachev

Ouvrez votre index.js (dossier racine):

  • Importez ReduxPromise à partir de 'redux-promise', n'oubliez pas de l'installer d'abord (npm install --save redux-promise)

import ReduxPromise from 'redux-promise';

  • ajoutez ReduxPromise à votre déclaration applyMiddleware

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

c. re-testez votre code.

0
Syarip Hidayat

si vous allez dans votre fichier d’index principal (pas celui dans le dossier actions mais un dans le dossier src) .. et assurez-vous que vous avez les lignes suivantes.

  1. importer ReduxPromise à partir de 'redux-promise';)
  2. importer {createStore, applyMiddleware} depuis 'redux';
  3. const createStoreWithMiddleware = applyMiddleware (ReduxPromise) (createStore);
  4. Ajoutez la propriété suivante à la balise Provider => store = {createStoreWithMiddleware (réducteurs)}

    Où les réducteurs proviennent du fichier de réducteurs combinés (./reducers).

0
kam bajwa

import axios from 'axios';

const API_KEY = 'xxxxxxxxx';
const ROOT_URL = `http://api.openweathermap.org/data/2.5/forecast?appid=${API_KEY}`;

export const FETCH_WEATHER = 'FETCH_WEATHER';

export function fetchWeather(city) {
  const url = `${ROOT_URL}&q=${city},us`;
  const request = axios.get(url);

  //console.log("request:", request);

  return {
    type: FETCH_WEATHER,
    payLoad: request
  };
}

0
kam bajwa

J'ai lu les posts et les réponses, et tout le monde a raison .. mais il se peut que ReduxPromise ne soit pas installé dans vos dépendances .. vérifiez votre fichier package.json pour voir, puis exécutez ou réexécutez "npm install redux- promise --save ".. qui devrait résoudre le problème ..

vous devriez voir les dépendances comme celle-ci dans votre fichier package.json:

"dependencies": {
    "axios": "^0.18.0",
    "react": "16.3.2",
    "react-dom": "16.3.2",
    "react-redux": "5.0.7",
    "redux": "4.0.0",
    **"redux-promise": "^0.6.0"**
0
Richard Rosario

Je passais par le même problème, le problème ici est que vous n’avez pas appliqué la promesse à votre middleware dans la base index.js que vous avez. Dans votre index.js principal, vous devez inclure cette ligne de code:

const createStoreWithMiddleware = applyMiddleware (promis) (createStore);

Cela résoudra le problème.

0
Chris