0

When adding an object to an array with Redux, for some reason adding the first record would not work.

I would get the following error:

TypeError: Invalid attempt to spread non-iterable instance. in order to be iterable, non-array objects must have a [Symbolic.iterator]()method.

With this code:

case POST_COMMENTS_ADD:
  return {
    ...state,
    comments: [...state.comments, action.newItem[0]],
    lastKey: null,
    noData: null,
  };

I would like to understand why this approach was not working when I feel like it should have been.

Here is how I managed it to add (first record without an error - all subsequent adds worked fine with the initial code)

case POST_COMMENTS_ADD:
  return {
    ...state,
    comments: !state.comments ? [action.newItem[0]] : [...state.comments, action.newItem[0]],
    lastKey: null,
    noData: null,
  };

The fix works, but I'd like to see where I went wrong with the first approach.

Here is my entire reducer:

  import {
    POST_COMMENTS_FETCH_SUCCESS,
    POST_COMMENTS_NO_DATA,
    UNMOUNT_POST_COMMENTS,
    POST_COMMENTS_ADD,
  } from '../actions/types';

  const INITIAL_STATE = {
    comments: [],
  };

  export default (state = INITIAL_STATE, action) => {
    switch (action.type) {
      case POST_COMMENTS_FETCH_SUCCESS:
        return {comments: action.payload, lastKey: action.key, noData: null};
      case POST_COMMENTS_NO_DATA:
        return {comments: null, lastKey: null, noData: true};
      case POST_COMMENTS_ADD:
        return {
          ...state,
          comments: !state.comments ? [action.newItem[0]] : [action.newItem[0], ...state.comments],
          lastKey: null,
          noData: null,
        };
      case UNMOUNT_POST_COMMENTS:
        return {comments: null, noData: null};
      default:
        return state;
    }
  };
hugger
  • 426
  • 4
  • 19
  • What happens if you log the state before the return statement, I'm guessing your state.comments is not an array at that moment? – jean182 Apr 02 '20 at 20:23
  • My initial state looks like this: const INITIAL_STATE = { comments: [], }; – hugger Apr 02 '20 at 20:25
  • 1
    Yeah that looks good, but on the POST_COMMENTS_ADD, what is returning at that time, maybe the state.comments is changing somewhere else? – jean182 Apr 02 '20 at 20:27
  • Initially the comments are being fetched, but only once. if there is data to fetch it would add comments fine, but when nothing is fetched the array is empty (according to the initial state) - then the only time it changes from there is when the comment is added. – hugger Apr 02 '20 at 20:31
  • Can you post the entire reducer file ? Although you fixed it using an if check, it should work without that if initial state is properly set. – Subin Sebastian Apr 02 '20 at 20:59
  • @ssk I just added the entire reducer, thank you. – hugger Apr 02 '20 at 21:05
  • I switched around the spread operator to add the item to the opposite side, incase you were wondering – hugger Apr 02 '20 at 21:06

1 Answers1

3

Your default initialState seems fine, But we can see that in couple of actions(POST_COMMENTS_NO_DATA and UNMOUNT_POST_COMMENTS) you are setting comments as null. Instead, it should be set as []. So even though state is initialized with comments as [] it is later changed as null as either of these actions are fired before POST_COMMENTS_ADD

case POST_COMMENTS_NO_DATA:
        return {comments: [], lastKey: null, noData: true};
  case UNMOUNT_POST_COMMENTS:
        return {comments: [], noData: null};
Subin Sebastian
  • 10,870
  • 3
  • 37
  • 42