2017-02-22 1 views
1

Je viens de commencer à expérimenter avec rea et redux et je suis confronté à quelques problèmes en cours de route.Réagir avec redux et Reagent-routeur envoie deux fois l'action

Lorsque j'essaie de rendre des données asynchrones lors d'un changement de route, l'action envoyée est renvoyée deux fois. Le premier est indéfini et les vraies données viennent.

Voici mon magasin

import { createStore, combineReducers, applyMiddleware } from 'redux' 
import createLogger from 'redux-logger' 
import thunk from 'redux-thunk' 
import { routerReducer, routerMiddleware, push } from 'react-router-redux' 
import reducers from '../reducers' 
import { browserHistory } from 'react-router'; 

const middleware = [ thunk ]; 
if (process.env.NODE_ENV !== 'production') { 
    middleware.push(createLogger()); 
} 

middleware.push(routerMiddleware(browserHistory)); 


    // Add the reducer to your store on the `routing` key 
    const store = createStore(
     combineReducers({ 
      reducers, 
      routing: routerReducer 
     }), 
     applyMiddleware(...middleware), 

    ) 

    export default store; 

réducteur

export const RESOLVED_GET_PROFILE = 'RESOLVED_GET_PROFILE' 

const profileReducer = (state = {}, action) => { 
    switch (action.type) { 
     case 'SET_PROFILE': 
       return {profile: action.profile} 

     default: 
      return state; 
    } 
}; 

export default profileReducer; 

actions

import * as types from './actionTypes'; 
import Api from '../middleware/Api'; 

export function getProfile() { 
    return dispatch => { 
     dispatch(setLoadingProfileState()); // Show a loading spinner 
     Api.get('profile').then(profile => { 
      dispatch(doneFetchingProfile); 
      dispatch(setProfile(profile)); 
     }).catch(error => { 
      dispatch(showError(error)); 
      throw(error); 
     }); 
    } 
} 

function setProfile(data) { 
    return { 
     type: types.SET_PROFILE, 
     profile: data 
    } 
} 


function setLoadingProfileState() { 
    return { 
     type: types.SHOW_SPINNER, 
     loaded: false 
    } 
} 

function doneFetchingProfile() { 
    return { 
     type: types.HIDE_SPINNER, 
     loaded: true 
    } 
} 

function showError() { 
    return { 
     type: types.SHOW_ERROR, 
     loaded: false, 
     error: 'error' 
    } 
} 

et voici mon composant

import React, {PropTypes, Component} from 'react'; 
import {bindActionCreators} from 'redux'; 
import {connect} from 'react-redux'; 
import * as profileActions from '../../../actions/profileActions'; 


class Profile extends Component { 

    static propTypes = { 
     profile: PropTypes.object.isRequired, 
    }; 

    constructor(props) { 
     super(props); 

     this.state = { 
      profile:{ 
       username: '', 
       password: '', 
       email: '' 
      } 
     } 
     this.onUpdate = this.onUpdate.bind(this) 
    } 

    onUpdate(event) { 
     alert() 
    } 

    componentDidMount() { 
     //here I dispatch the action 
     this.props.actions.getProfile() 
    } 

    componentWillReceiveProps(nextProps) { 

    } 

    render() { 
     console.log(this.props) 
     //this.props.profile on first is undefined and then filled 
     const { profile } = this.props.profile 

     return (
      <div> 

      </div> 
     ); 
    } 
} 

function mapStateToProps(state) { 

    return { 
     profile: state.default.profile, 
    }; 
} 

function mapDispatchToProps(dispatch) { 
    return { 
     actions: bindActionCreators(profileActions, dispatch) 
    }; 
} 

export default connect(mapStateToProps, mapDispatchToProps)(Profile); 

qu'est-ce que je me trompe?

console

Répondre

0

Vous avez dit //this.props.profile on first is undefined and then filled

C'est parce que dans le premier rendu, state.profileestundefined, jusqu'à ce que la réponse à la demande arrive et l'action setProfile est envoyé.

Il y a aussi le problème Andrew a noté que vous appelez dispatch(doneFetchingProfile). Puisque vous utilisez redux-thunk, cela déclenchera l'appel doneFetchingProfile(dispatch, getState), mais l'action HIDE_SPINNER ne sera jamais envoyée.


MISE À JOUR: Il n'y a rien de mal avec votre code. Vous pouvez voir avant SHOW_SPINNER la sortie de console.log(this.props) et il n'y a pas profile parce qu'il n'y a pas profile en état aussi bien.

Ensuite, lorsque votre requête réussit, profile est défini dans l'état, puis transmis à votre composant, puis vous pouvez voir dans le journal que profile est défini. Ce ne sont pas des actions expédiées, c'est le journal de vos accessoires.

La première fois est indéfinie car l'état initial déclaré dans le réducteur est {} (il n'y a pas ici non plus profile).

Si vous changez

const profileReducer = (state = {}, action) => { 

à

const profileReducer = (state = {profile: 'some initial value'}, action) => { 

vous verrez que le premier console.log(this.props) montrera profile avec la valeur 'some initial value' puis modifier les données à distance.

+0

alors j'ai essayé dispatch (doneFetchingProfile (profile)) et le profil de retour, mais même si c'est la même chose. Comment refactoriser le code à déclencher une fois avec les données? – fefe

+0

@fefe Je ne comprends pas. Comment regardez-vous les actions qui sont expédiées? Selon le code 'SET_PROFILE' ne devrait être envoyé qu'une seule fois. Mais 'state.profile' suppose 2 valeurs: commence par' undefined' et est ensuite défini sur les données correctes, après l'envoi de l'action ci-dessus. – Lucas

+0

J'ai fait une capture d'écran de la console – fefe

0

Vous dispatching 2 actions

dispatch(doneFetchingProfile); 
dispatch(setProfile(profile)); 

premier d'entre eux ont pas de données, et il est ressembler à action tihs mis à l'état des données et mettre à jour votre composant.

+0

En fait, avec redux-thunk qui n'exécutera simplement aucune action concernant "définir le profil" – Lucas

1

C'est ce qui se passe ici

  1. rendre votre composant et afficher non défini sur la console parce qu'il n'y a pas de données à ce jour.
  2. Après le montage du composant, appelez componentDidmount qui déclenche une action pour extraire les données de l'URL.

  3. Vous obtenez des données d'api et mettez à jour l'état redux qui met également votre composant à jour.

  4. Par conséquent, la fonction de rendu est appelée à nouveau et cette fois affiche les données de profil.

Il n'y a rien envoi deux fois. Le code est parfaitement bien.