3

Please refer to the below function for this question:

const mapStateToProps = (state) => {
  return {
    currentPlaylist: state.currentPlaylist,
    currentSong: state.currentSong,
    localPlaylists: state.playlistsBySource['local'],
    videoSize: state.videoSize,
  };
}

This is mapStateToProps function for a container. I expected the component that's connected to this container to be re-rendered every time state.playlistsBySource['local'] was updated. However, it didn't render even if state.playlistsBySource['local'] updated so I changed the code to below:

const mapStateToProps = (state) => {
  return {
    currentPlaylist: state.currentPlaylist,
    currentSong: state.currentSong,
    playlists: state.playlistsBySource,
    videoSize: state.videoSize,
  };
}

Then the connected component was correctly updated every time state.playlistsBySource['local'] was updated. But this is a kind of a waste because the connected component does not need the entire playlists.

Why is this exactly happening, and what's the correct way to solve it?

Update

I connect the component like this:

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

The render method of DumbComponent doesn't get called when state.playlistsBySource['local'] has been updated in the global store.

UPDATE2: Reducer seems to be immutable.. am I missing something?

case CONSTANTS.UPDATE_LOCAL_PLAYLIST:
  var playlistUpdated = transformedPlaylist(state[action.playlist.source], action);
  return updatedPlaylists(playlistUpdated, state);

function transformedPlaylist(state=[], action) {
  var oldPlaylist = _.find(state, (pl) =>
    pl.playlistName === action.playlist.playlistName);

  switch (action.type) {
    case CONSTANTS.RECEIVE_PLAYLIST:
    case CONSTANTS.UPDATE_LOCAL_PLAYLIST:
      return Object.assign({}, oldPlaylist, action.playlist, {
        isFetching: false,
      });
    default:
      return oldPlaylist
  }
}

function updatedPlaylists(playlistUpdated, oldPlaylists) {
  const source = playlistUpdated.source;
  const idxToUpdate = _.findIndex(oldPlaylists[source], (pl) =>
    pl.playlistName === playlistUpdated.playlistName
  );
  var playlists = Object.assign({}, oldPlaylists);
  playlists[source][idxToUpdate] = playlistUpdated;
  return playlists;
}
2
  • when you say "the component that's connected to this container", do you mean a component that's rendered by this container? or simply that the render method of this connected react component doesn't get called when state.playlistsBySource.local is updated in the store? Commented Apr 6, 2016 at 18:07
  • @ZekeDroid I updated the question. I think the latter is what I meant. Commented Apr 6, 2016 at 18:11

1 Answer 1

7

It would help if you could post the relevant code for your reducer. However, the vast majority of the time, the reason your component isn't updating is because you're directly mutating state in your reducer, instead of returning modified copies immutably. See the Redux FAQ answer at http://redux.js.org/docs/FAQ.html#react-not-rerendering for more information.

Update:

This line looks suspicious: playlists[source][idxToUpdate] = playlistUpdated;

Remember, if you are updating nested data immutably, you have to return copied and updated items all the way up to the top of your data.

It's a bit hard to tell exactly without seeing your whole state structure and actions in context, but I think it's pretty likely you are indeed doing direct mutation in one of your nested fields.

Sign up to request clarification or add additional context in comments.

2 Comments

The line directly above that does var playlists = Object.assign({}, oldPlaylists); thought. Doesn't that make it immutable?
That's a shallow copy. It copies the upper-level object's fields over, but those fields still point to the same nested data. So, if you directly write to a nested object, you've directly mutated it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.