2017-02-22 51 views
1

我剛開始嘗試react和redux,並且我在路上遇到了一些問題。與redux和react-router分派動作兩次作出反應

當我嘗試渲染路由上的異步數據時,分派的動作會被觸發兩次。首先是未定義的,而不是真實的數據。

這裏是我的商店

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; 

減速

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; 

行動

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

,這裏是我的組件

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

我錯了什麼?

console

回答

0

你說//this.props.profile on first is undefined and then filled

這是因爲在第一渲染,state.profileundefined,直到請求響應到達和setProfile行動出動。

還有問題安德魯指出,你打電話dispatch(doneFetchingProfile)。由於您使用的是複合強化,因此會觸發doneFetchingProfile(dispatch, getState),但操作HIDE_SPINNER將永遠不會分派。


UPDATE:沒有什麼你的代碼錯誤。您可以在SHOW_SPINNER之前看到console.log(this.props)的輸出,並且沒有profile,因爲狀態中也沒有profile

然後,當您的請求成功時,profile設置爲狀態,然後傳遞給您的組件,然後您可以在日誌中看到設置了profile。這些不是行動派遣,這是你的道具的日誌。

第一次未定義,因爲在reducer中聲明的初始狀態是{}(這裏也沒有profile)。

如果更改

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

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

,你會看到第一個console.log(this.props)將顯示profile與價值'some initial value',然後切換到遠程數據。

+0

的操作,因此我嘗試調度(doneFetchingProfile(配置文件))並返回配置文件,但即便如此也是如此。我該如何重構代碼才能被數據觸發一次? – fefe

+0

@fefe我不明白。你如何看待分派哪些操作?根據代碼「SET_PROFILE」只應該調度一次。但'state.profile'假設2個值:以undefined開頭,然後在調度上述操作後設置爲正確的數據。 – Lucas

+0

我從控制檯做了一個截圖 – fefe

0

您派遣2個行動

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

他們首先沒有數據,它的樣子設定狀態的一些數據和更新組件tihs行動。

+0

實際上,使用redux-thunk將不會發送任何有關「設置配置文件」 – Lucas

1

這就是發生在這裏

  1. 你的組件渲染並在控制檯上顯示未定義因爲沒有配置文件數據爲止。
  2. 組件掛載後,調用componentDidmount,它觸發一個動作從url中獲取數據。

  3. 您從api獲取數據並更新更新組件的redux狀態。

  4. 因此,您再次調用渲染函數,這次它顯示配置文件數據

沒有任何調度兩次。代碼非常好。