4

I'm making a recipe box App, and I decided to start by my handleTitle and handleInput methods. I was able to pull that out, but now I want to make an array of objects (the objects contain the title and the description) and then I would map through this array and display the data.

but my handleSubmit function is not working the way I wanted. I want the user to be able to write several titles and descriptions, and those will keep being added to the recipes array in the state. Take a look at the code:

import React, { useState } from "react";
import "./styles.css";

import { Form } from "./components/containers/Form";

export default function App() {
  const [title, setTitle] = useState("");
  const [description, setDescription] = useState("");
  const [recipe, setRecipe] = useState([]);

  const handleTitle = e => {
    setTitle(e.target.value);
  };

  const handleDescription = e => {
    setDescription(e.target.value);
  };

  const handleSubmit = e => {
    e.preventDefault();
    if (title !== "" && description !== "") {
      setRecipe(prevState => {
        const data = { title: title, description: description };

        return {
          ...prevState,
          recipe: prevState.recipe.concat(data)
        };
      });
    }
  };

  return (
    <div className="App">
      <Form
        title={title}
        description={description}
        handleTitle={handleTitle}
        handleDescription={handleDescription}
        handleSubmit={handleSubmit}
      />
    </div>
  );
}
import React from "react";

export const Form = ({
  handleTitle,
  handleDescription,
  handleSubmit,
  title,
  description
}) => {
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          onChange={handleTitle}
          placeholder="title"
          value={title}
        />

        <input
          type="text"
          onChange={handleDescription}
          placeholder="description"
          value={description}
        />
        <button>Add</button>
      </form>
    </div>
  );
};
Amir
  • 1,328
  • 2
  • 13
  • 27
gabriel_tiso
  • 1,007
  • 3
  • 11
  • 27
  • If you are going to do a lot of forms, I suggest using [Formik](https://jaredpalmer.com/formik). – Lekoaf May 22 '20 at 13:04
  • 1
    `recipe` is an array, so you need to set it to `[...prevState, data]`. –  May 22 '20 at 13:06
  • Does this answer your question? [Push method in React Hooks (useState)?](https://stackoverflow.com/questions/54676966/push-method-in-react-hooks-usestate) –  May 22 '20 at 13:08

1 Answers1

1

When you set the recipes, you're changing the primitive type of recipes state to an object. Instead you should just return a new array with the previous recipes and the new recipe.

I've attached a runnable example below:

const Form = ({
  handleTitle,
  handleDescription,
  handleSubmit,
  title,
  description
}) => {
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          onChange={handleTitle}
          placeholder="title"
          value={title}
        />

        <input
          type="text"
          onChange={handleDescription}
          placeholder="description"
          value={description}
        />
        <button>Add</button>
      </form>
    </div>
  );
};

function App() {
  const [title, setTitle] = React.useState("");
  const [description, setDescription] = React.useState("");
  const [recipes, setRecipes] = React.useState([]);

  const handleTitle = e => {
    setTitle(e.target.value);
  };

  const handleDescription = e => {
    setDescription(e.target.value);
  };

  const handleSubmit = e => {
    e.preventDefault();
    if (title !== "" && description !== "") {
      setRecipes(prevState => {
        const data = { title: title, description: description };
        return [...prevState, data];
      });
      setTitle("");
      setDescription("");
    }
  };

  return (
    <div className="App">
      <Form
        title={title}
        description={description}
        handleTitle={handleTitle}
        handleDescription={handleDescription}
        handleSubmit={handleSubmit}
      />
      <h5>Recipes</h5>
      {recipes.length === 0
        ? (
          <div>No recipes</div>
        )
        : (
        <ul>
          {recipes.map(({ title, description }) => (
            <li>
              {title} : {description}
            </li>
          ))}
        </ul> 
      )}
    </div>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Win
  • 5,498
  • 2
  • 15
  • 20