最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React-redux, connect function does not update the state with the new data - Stack Overflow

programmeradmin0浏览0评论

I am using Redux as a Flux alternative and React for the view layer. My application's React and Redux are bound with react-redux connect() method. When running the application it dispatches the action when the ponents mounts and the redux returns the correct state. However the redux-logger logs in the console that the store has updated with the new state, in the ponent when checking this.props.session it still shows the old state. I am guessing that I'm not using the connect method correctly, however I can't define the issue with it as well. Does anyone have an idea whats going on?

containers/App

'use strict';

import React from 'react';
import {connect} from 'react-redux';
import {fetchUserSession} from 'actions/SessionActions';

class App extends React.Component {
  constructor(props) {
    super(props);
  }
  ponentWillMount() {
    const {dispatch, session} = this.props;
    dispatch(fetchUserSession());
    console.log(session);
    // logs:
    // Object {currentUserId: null, errorMessage: null, isSessionValid: null}

    // store is bound to window, and the initial state is ImmutabeJS object
    console.log(window.store.getState().session.toJS());
    // logs:
    // Object {currentUserId: null, errorMessage: null, isSessionValid: false}
    // as you might noticed the isSessionValid is changed to false
  }

  render() {
    // html here 
  }
}

function mapStateToProps(state){
  return {
    session: state.session.toJS()
  };
}

export default connect(mapStateToProps)(App);

actions/Actions.js

'use strict';

import fetch from 'isomorphic-fetch';

export const SESSION_REQUEST = 'SESSION_REQUEST';
export const SESSION_SUCCESS = 'SESSION_SUCCESS';

export function requestSession() {
  return {
    type: SESSION_REQUEST
  };
}

export function receiveSession(user) {
  return {
    type: SESSION_REQUEST,
    user
  };
}

export function fetchUserSession() {
  return dispatch => {
    dispatch(requestSession());
    return fetch(`http://localhost:5000/session`)
      .then((response) => {
        if (response.status === 404) {
          dispatch(raiseSessionFailure(response));
        }
        return response.json();
      })
      .then(userData => dispatch(receiveSession(userData)));
  };
}

reducers/SessionReducer.js

'use strict';
import {fromJS} from 'immutable';

// UPDATE!!!
// here is the initial state
const initialState = fromJS({
  currentUserId: null,
  errorMessage: null,
  isSessionValid: null
});

function sessionReducer(state = initialState, action) {
  switch (action.type) {
    case 'SESSION_REQUEST':
      return state.update('isSessionValid', () => false);
    case 'SESSION_SUCCESS':
      console.log('Reducer: SESSION_SUCCESS');
      return state;
    case 'SESSION_FAILURE':
      console.log('Reducer: SESSION_FAILURE');
      return state;
    default:
      return state;
  }
}

export default sessionReducer;

reducers/RootReducer

'use strict';

import {bineReducers} from 'redux';
import sessionReducer from 'reducers/SessionReducer';

const rootReducer = bineReducers({
  session: sessionReducer
});

export default rootReducer;

I am using Redux as a Flux alternative and React for the view layer. My application's React and Redux are bound with react-redux connect() method. When running the application it dispatches the action when the ponents mounts and the redux returns the correct state. However the redux-logger logs in the console that the store has updated with the new state, in the ponent when checking this.props.session it still shows the old state. I am guessing that I'm not using the connect method correctly, however I can't define the issue with it as well. Does anyone have an idea whats going on?

containers/App

'use strict';

import React from 'react';
import {connect} from 'react-redux';
import {fetchUserSession} from 'actions/SessionActions';

class App extends React.Component {
  constructor(props) {
    super(props);
  }
  ponentWillMount() {
    const {dispatch, session} = this.props;
    dispatch(fetchUserSession());
    console.log(session);
    // logs:
    // Object {currentUserId: null, errorMessage: null, isSessionValid: null}

    // store is bound to window, and the initial state is ImmutabeJS object
    console.log(window.store.getState().session.toJS());
    // logs:
    // Object {currentUserId: null, errorMessage: null, isSessionValid: false}
    // as you might noticed the isSessionValid is changed to false
  }

  render() {
    // html here 
  }
}

function mapStateToProps(state){
  return {
    session: state.session.toJS()
  };
}

export default connect(mapStateToProps)(App);

actions/Actions.js

'use strict';

import fetch from 'isomorphic-fetch';

export const SESSION_REQUEST = 'SESSION_REQUEST';
export const SESSION_SUCCESS = 'SESSION_SUCCESS';

export function requestSession() {
  return {
    type: SESSION_REQUEST
  };
}

export function receiveSession(user) {
  return {
    type: SESSION_REQUEST,
    user
  };
}

export function fetchUserSession() {
  return dispatch => {
    dispatch(requestSession());
    return fetch(`http://localhost:5000/session`)
      .then((response) => {
        if (response.status === 404) {
          dispatch(raiseSessionFailure(response));
        }
        return response.json();
      })
      .then(userData => dispatch(receiveSession(userData)));
  };
}

reducers/SessionReducer.js

'use strict';
import {fromJS} from 'immutable';

// UPDATE!!!
// here is the initial state
const initialState = fromJS({
  currentUserId: null,
  errorMessage: null,
  isSessionValid: null
});

function sessionReducer(state = initialState, action) {
  switch (action.type) {
    case 'SESSION_REQUEST':
      return state.update('isSessionValid', () => false);
    case 'SESSION_SUCCESS':
      console.log('Reducer: SESSION_SUCCESS');
      return state;
    case 'SESSION_FAILURE':
      console.log('Reducer: SESSION_FAILURE');
      return state;
    default:
      return state;
  }
}

export default sessionReducer;

reducers/RootReducer

'use strict';

import {bineReducers} from 'redux';
import sessionReducer from 'reducers/SessionReducer';

const rootReducer = bineReducers({
  session: sessionReducer
});

export default rootReducer;
Share Improve this question edited Sep 25, 2015 at 11:14 Max asked Sep 25, 2015 at 9:53 MaxMax 2,5156 gold badges37 silver badges54 bronze badges 8
  • 1 can you show what your state looks like? I think because you're not bining the reducers it'll look just like the initialState can you also include this too? – Clarkie Commented Sep 25, 2015 at 10:49
  • Hi @Clarkie I updated the reducer and put well how I bine the reducers – Max Commented Sep 25, 2015 at 11:15
  • 1 have you tried getting it to work without using the immutableJS lib? I've only ever used redux with the immutability helpers from react – Clarkie Commented Sep 25, 2015 at 11:36
  • What version of redux and react-redux are you running? There might have been issues in pre-1.0 versions. – Dan Abramov Commented Oct 3, 2015 at 14:45
  • 2 I'm not sure that this relates directly to the issue you are having, but the way you are logging to the console in ponentWillMount is guaranteed to log different results for the session prop and the session in the store. The call to dispatch will update the store synchronously, but you won't see a new session prop until after ponentWillMount has pleted. Can you verifying this by logging this.props.session in a setTimeout instead of immediately after the call to dispatch? – lukewestby Commented Oct 4, 2015 at 16:20
 |  Show 3 more ments

2 Answers 2

Reset to default 5

The issue is with the way the session variable is being logged from props and from the store. When you dispatch the action to update state it is synchronously updating the store, which is why you see that the store has been updated when you log it directly. However, react-redux won't be able to update props until the call to ponentWillMount has pleted and React has had a chance to catch up and rerender the ponent with the new state. If you dispatch the action in ponentWillMount and log the session prop at a later time you will see that it has changed to reflect the action.

Looks like you don't change state in action handlers in reducer. Only case with other than return state code says state.update('isSessionValid', () => false) — what does it return? If it's the same object as previous state, redux wouldn't change anything because of immutability convention.

发布评论

评论列表(0)

  1. 暂无评论