0

I am trying to dynamically add state to an array from my form in such a way that multiple inputs can eventually be saved as state in the same array, much like the redux form but I don't know Redux yet.

I don't know how to access the current array I am in so I can set the current input value as state. In this case, I am trying to save the name of the ingredient inside the ingredient array within the recipe state by mapping over the current array. Problem is when I try to map over the current array it apparently isn't an array at all and I get the following error when I try to enter data into the input..

TypeError: currentIngredients.map is not a function
(anonymous function)
src/components/recipes/Recipe_Form.js:68
  65 | <input
  66 |   onChange={e => {
  67 |     const name = e.target.value;
> 68 |     setRecipe((currentIngredients) =>
     | ^  69 |       currentIngredients.map(x =>
  70 |         x.id === i.id
  71 |           ? {

. I am unsure how to access the ingredient array in such a way that I can edit state.

thanks

export const Recipe_Form = () => {
  const recipeContext = useContext(RecipeContext);

  const [recipe, setRecipe] = useState({
    title: "",
    img: "",
    ingredients: [{ id: "1", name: "cheese", amount: "200" }],
    method: "",
    serves: "",
    time: "",
  });

  const onChange = (e) =>
    setRecipe({ ...recipe, [e.target.name]: e.target.value });

  const onSubmit = (e) => {
    e.preventDefault();
    recipeContext.addRecipe(recipe);
    setRecipe({
      title: "",
      img: "",
      ingredients: [],
      method: "",
      serves: "",
      time: "",
    });
  };

  const { title, img, ingredients, method, serves, time } = recipe;

  return (
    <div className='row center-align'>
      <form className='col s12' onSubmit={onSubmit}>
        {/* Image */}
        <div className='input-field col s12 center-align'>
          <input
            type='text'
            placeholder='Please enter an image url'
            name='img'
            value={img}
            onChange={onChange}
          />
        </div>
        {/* Title */}
        <div className='input-field col s12 center-align'>
          <input
            type='text'
            placeholder='Please enter recipe title'
            className='validate'
            name='title'
            value={title}
            onChange={onChange}
          />
        </div>

        {ingredients.map((i) => {
          return (
            <div key={i.id}>
              <input
                onChange={(e) => {
                  const name = e.target.value;
                  setRecipe((currentIngredients) =>
                    currentIngredients.map((x) =>
                      x.id === i.id
                        ? {
                            ...x,
                            name,
                          }
                        : x
                    )
                  );
                  // e.target.value
                }}
                value={i.name}
                placeholder='ingredient'
              />

              <input value={i.amount} placeholder='amount' />
            </div>
          );
        })}
        {/* Method */}
        <div className='methodContainer'>
          <div className='row method-line'>
            <div className='input-field col s12 center-align'>
              <input
                type='text'
                placeholder='Please enter method'
                className='validate'
                name='method'
                value={method}
                onChange={onChange}
              />
            </div>
          </div>
        </div>
        <a className='btn-floating btn-large waves-effect waves-light red'>
          <i className='fas fa-plus'></i>
        </a>
        {/* Serves */}
        <div className='input-field col s12 center-align'>
          <input
            type='number'
            placeholder='Number of servings'
            className='validate'
            name='serves'
            value={serves}
            onChange={onChange}
          />
        </div>
        {/* Time */}
        <div className='input-field col s12 center-align'>
          <input
            type='text'
            placeholder='Time to compelete...'
            className='validate'
            name='time'
            value={time}
            onChange={onChange}
          />
        </div>
        <br></br>
        <button
          className='btn waves-effect waves-light'
          type='submit'
          name='action'>
          Submit
        </button>
      </form>
    </div>
  );
};

export default Recipe_Form;

1 Answer 1

1

Isn't this, because the currentIngredients is actually your state object? you don't have to use it that way. You can do something like that:

setRecipe({
  ...recipe,
  ingredients: recipe.ingredients.map(x =>
    x.id === i.id
      ? {
          ...x,
          name
        }
      : x
  )
});

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

Comments

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.