TypeError: can't access property Symbol.iterator, state[action.payload.savedVideos] is undefined

347 views Asked by At

I have a problem with redux. I am working on an app where you can save a note about your youtube video. Everything is working fine, but when I started adding the 'ADD_ITEM' action I have the same mistake every time with this action in my reducer. The error I have is: TypeError: can't access property Symbol.iterator, state[action.payload.savedVideos] is undefined. I am using connect method and function mapDispatchToProps seems fine, so maybe the problem is in reducer or action creator. Here is my add item function in my reducer: `

 const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        ...state,
        [action.payload.savedVideos]: [...state[action.payload.savedVideos], action.payload.item],
      };

here is my action creator:

 export const addItem = (itemContent, savedVideos) => {
  const getId = () => `_${Math.random().toString(36).substr(2, 9)}`;

  return {
    type: 'ADD_ITEM',
    payload: {
      savedVideos,
      item: {
        id: getId(),
        ...itemContent,
      },
    },
  };
};

and my initial state:

const initialState = {
  saves: [
    {
      id: 1,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHh-kU',
      content: 'Nowy film gargamela!',
    },
    {
      id: 2,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHa-kU',
      content: 'Nowy film!',
    },
    {
      id: 3,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHy-kU',
      content: 'Nowy film gorgonzoli!',
    },
    {
      id: 4,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHy-kU',
      content: 'Nowy film gorgonzoli!',
    },
    {
      id: 5,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHy-kU',
      content: 'Nowy film gorgonzoli!',
    },
  ],
};



2

There are 2 answers

4
Someone Special On

https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers#creating-the-root-reducer

Assuming savedVideos is from the initialState, when u add video, you are adding the following object, and you want to add on to your initialState (aka initial store), you do not need to pass savedVideos to actions and reducer.

{
      id: 1,
      title: 'Hello meow',
      created: '18 may 2018',
      link: 'https://www.youtube.com/watch?v=-QmyosHh-kU',
      content: 'Nowy film gargamela!',
},

Your action can be..

 export const addItem = (itemContent, savedVideos) => {
  const getId = () => `_${Math.random().toString(36).substr(2, 9)}`;

  return {
    type: 'ADD_ITEM',
    payload: {
        id: getId(),
        ...itemContent,
      },
  };
};

Your reducer can be

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return { ...state, saves: [...state.saves, action.payload]  }
      //or whatever new item u need to add to the state (store).
    case 'DELETE_ITEM': //bonus
      return { ...state, saves: state.saves.filter( x => x.id !== action.payload.id) }
}
1
Linda Paiste On

I want to explain the error

"TypeError: can't access property Symbol.iterator, state[action.payload.savedVideos] is undefined"

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        ...state,
        [action.payload.savedVideos]: [...state[action.payload.savedVideos], action.payload.item],
      };

What you are actually doing in your reducer is updating a property name from a variable. Square brackets around a property name means that it's a variable.

The property name is the value of action.payload.savedVideos. But that's not a valid property name because action.payload.savedVideos is an array (a Symbol.iterator).

You don't need a dynamic property name because you are always updating the property saves. As explained by @Someone Special, you don't need to include the existing savedVideos in your action either because you can already access them from the state.

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        ...state,
        saves: [...state.saves, action.payload.item],
      };