Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Redux Store updating, but component not re-rendering

Using the terminal to test my dispatched actions, Redux-logger shows that my state is being correctly updated. However, my component is not re-rendering as a result of the state change. I've looked at the SO answers regarding component not re-rendering, a majority of the responses claim that the state is being mutated; as a result, Redux won't re-render. However, I'm using Lodash's merge to deep-dup an object, I'm pretty sure I'm not returning a modified object. (Please see attached snippet below)

Would love to hear some advice from you guys, pulling my hair out on this one!

const usersReducer = (state = {}, action) => {
  Object.freeze(state); // avoid mutating state

  console.log(state); 
  // returns an empty object  
  let newState = merge({}, state);
  console.log(newState); 
  // returns my state with my dispatched action object inside  already???
  // newState for some reason already has new dispatched action
  switch (action.type) {
    case RECEIVE_USER:
      let newUser = {[action.user.id] = action.user};
      return merge(newUser, newUser);
    case RECEIVE_USERS:
      newState = {};
      action.users.forEach(user => {
        newState[user.id] = user;
      });
      return merge({}, newState);
    default:
      return state;
  }
};

React Container Component

import { connect } from 'react-redux';
import { receiveUsers, receiveUser, refreshAll, requestUsers, requestUser } from '../../actions/user_actions';
import allUsers from '../../reducers/selectors';
import UserList from './user_list';

const mapStateToProps = (state) => ({
  users: allUsers(state), // allUsers (selector that takes the state specfically the user Object and returns an array of user Objects)
  state
});

const mapDispatchToProps = (dispatch) => ({
  requestUser: () => dispatch(requestUser()),
  requestUsers: () => dispatch(requestUsers()),
  receiveUsers: (users) => dispatch(receiveUsers(users)),
  receiveUser: (user) => dispatch(receiveUser(user)),
  refreshAll: (users) => dispatch(refreshAll(users))
});

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

React Presentational component

import React from 'react';

class UserList extends React.Component {
  render() {
    const { users, state } = this.props;

    const userItems = users.map((user, idx) => {
        return(<li key={idx}>{user.username}</li>);
    });

    return (
      <div>
        <ul>
          { userItems }
        </ul>
      </div>
    );
  }
}

export default UserList;

React Store

import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import RootReducer from '../reducers/root_reducer';

const logger = createLogger();
const configureStore = (preloadedState = {}) => {
  return createStore(
    RootReducer, 
    preloadedState,
    applyMiddleware(logger));
};

// const configureStore = createStore(rootReducer, applyMiddleware(logger));

// oddly enough, when I have the store as a constant and not a function that returns the store constant, dispatching actions through the terminal will correctly update the state and rerender the component 

export default configureStore;

React Selector

const allUsers = ({ users }) => {
  return Object.keys(users).map(id => (
    users[id]
  ));
};

export default allUsers;
like image 716
Tonyhliu Avatar asked Jan 31 '17 17:01

Tonyhliu


2 Answers

I had a similar problem, just in case someone stumbles upon this, I needed to clone the array in order to re-render the view:

export const addFieldRow = () => (
    (dispatch: any, getState: any) => {
        const state = getState();
        const myArrayOfObjects = myArrayOfObjectsProp(state);
        const newObject = {
            key: "",
            value: "",
        };
        myArrayOfObjects.push(newObject);
        dispatch(addFieldRowAction({ myArrayOfObjects: [...myArrayOfObjects] })); <== here
    }
);
like image 82
Gus Avatar answered Sep 22 '22 05:09

Gus


Common problem in this case is using not reactive operations for changing state. For example use concat() for array, but not push() and so on.

like image 44
Artemy Prototyping Avatar answered Sep 20 '22 05:09

Artemy Prototyping