0

I spent two days trying to create reducer which changes the boolean for property toRecipe, without succes. This is nested array of objects. I cant move forward with it this is structure of array:

recipes: [ 
               { id: int, 
                 re: 'string',
                 c: [ 
                                  { id: int,
                                    co: 'string',
                                    toRecipe: false
                                  },
                                  {...}
                              ]
               },
               {...}
            ]

I have created a reducer like this:

case actionTypes.EDIT_BOOLEAN:
  return {
    ...state,
    recipes: {...state.recipes,
    [action.payload.idFromRecipe]: {...state.recipes[action.payload.idFromRecipe],
    c: {...state.recipes[action.payload.idFromRecipe].c,
    [action.payload.idFromComp]: {...state.recipes[action.payload.idFromRecipe].c[action.payload.idFromComp], toRecipe: false}
  }
  }
  }
}

but when I use this reducer I have error: TypeError: Cannot read property 'c' of undefined

I list this array here (bold text):

class RecipeList extends Component {

  render(){

    console.log(this.props.recipes.map(recipe=>recipe));
    let compons = this.props.recipes.map(recipe =>(
            <div key={recipe.id}>
            <h2>{recipe.re}</h2>
              <ul key={recipe.id}>
              {recipe.c.map(comp=> comp.toRecipe === true ?
                <li key={comp.id}>{comp.co}</li>
                : null
              )}
              </ul>
              <div>
                <form>
                 **{ recipe.c.map((comp, i)=>(
                  <div key={i}>
                <input
                  onChange={()=>this.props.editRecipes(comp.id,recipe.id)}
                  type="checkbox"
                  key={i}
                  checked={comp.toRecipe}
                />
                <label key={comp.id}>{comp.co}</label>

                </div>
              ))  }**
                </form>

              </div>
            </div>
      )
    );
    console.log(compons);
    return (
      <div>
        {compons}

      </div>
    )
  }
}

Could anyone help me?

2
  • could you please indent your reducer code? Commented Jun 5, 2018 at 9:58
  • state.recipes[action.payload.idFromRecipe].c must be undefined Commented Jun 5, 2018 at 10:01

1 Answer 1

2
You are trying to access property that doesn't exist yet

    return {
        ...state,
        recipes: {
            ...state.recipes,
            [action.payload.idFromRecipe]: {
                ...state.recipes[action.payload.idFromRecipe],
                c: {
                    ...state.recipes[action.payload.idFromRecipe].c,
                    [action.payload.idFromComp]: {
                        ...state.recipes[action.payload.idFromRecipe].c[action.payload.idFromComp],
                        toRecipe: false
                    }
                }
            }
        }
    };

So basically let's take an example where you are trying to get that nested object working. YOur action has payload which is idFromRecipe = "123",

are you entirely sure that state.recipes.123.c exist? because it seems like it doesn't so it returns undefined so lane  

     ...state.recipes[action.payload.idFromRecipe].c,

will fail as you cannot access property C of undefined. To make it work like that you would need to check beforehend that it exist like

c: state.recipes[action.payload.idFromRecipe] ? {
   ...state.recipes[action.payload.idFromRecipe].c,
                [action.payload.idFromComp]: {
                    ...state.recipes[action.payload.idFromRecipe].c[action.payload.idFromComp],
                    toRecipe: false
                }
} : {
                      ...state.recipes[action.payload.idFromRecipe].c[action.payload.idFromComp],
                    toRecipe: false
                }
}

Usually you should avoid such construction due to really odd logic afterwards and problem with optimization (as you pretty much need to change whole object each time). My suggestion is to actually Normalize state with normalizr e.g. and it will work better and there will be no such crazy logic as above.

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

1 Comment

this is crazy logic it is true. I though It will be more simple becose it is only array of objects in array of obcjects, so not very deep. I must learn normalize. Thank you!

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.