Home > Back-end >  Why do I need to submit twice for my mapped function to display the updated state after updating the
Why do I need to submit twice for my mapped function to display the updated state after updating the

Time:08-12

I am trying to display an img for the current value in the array item, but onl oad, when I submit my value, the image does not display. I submit twice to display the value. When changing the value and pressing submit, the div does not update the content with new value, but repeats the old one. After submitting again, the div is updated with new value.

export default function Ingredients() {
  const [form, setForm] = useState("");
  const [theimg, setheimg] = useState({
    name: "",
    url: "",
    id: "",
  });
  const [imgArr, setImgArr] = useState([]);

  function handleChange(e) {
    setForm(e.target.value);
  }

  function getImg() {
    const options = {
      method: "GET",
      headers: {
        "X-RapidAPI-Key": "29a63a7413msh8378b61a2e11cf3p192e62jsn53d83f1651fe",
        "X-RapidAPI-Host": "edamam-food-and-grocery-database.p.rapidapi.com",
      },
    };
    fetch(
      `https://edamam-food-and-grocery-database.p.rapidapi.com/parser?ingr=${form}`,
      options
    )
      .then((response) => response.json())
      .then((response) =>
        setheimg((prevImg) => ({
          ...prevImg,
          name: form,
          url: response.parsed[0].food.image,
          id: Math.random(),
        }))
      )
      .catch((err) => console.error(err));
  }

  const thingsElements = imgArr.map((thing) => (
    <div key={thing.id}>
      <img src={thing.url} />
      <p>{thing.name}</p>
    </div>
  ));

  return (
    <>
      <Navbar page="/" />
      <Heading heading="Ingredients" info="Search by etc" />
      <Form
        label="Search Ingredients..."
        onChange={handleChange}
        value={form.value}
        imgsrc={theimg}
      />
      <button
        onClick={() => {
          getImg();
          setImgArr((oldArray) => {
            return [...oldArray, theimg];
          });
        }}
      >
        Search
      </button>
      {thingsElements}
    </>
  );
}
const Form = (props) => {
  return (
    <>
      <label>
        {props.label}
        <input value={props.value} onChange={props.onChange} />
      </label>
    </>
  );
};
export default Form;

CodePudding user response:

In your click handler, you aren't waiting for getImg() to complete before adding theimg to the array.

Try something like this instead

const getImg = async () => {
  const params = new URLSearchParams({ ingr: form });
  const res = await fetch(`https://example.com/parser?${params}`, {
    method: "GET",
    headers: {
      "X-RapidAPI-Key": "<api-key>",
      "X-RapidAPI-Host": "<host>",
    },
  });

  if (!res.ok) {
    throw res;
  }

  const data = await response.json();
  return {
    name: form,
    url: data.parsed[0].food.image,
    id: Math.random(), // recommend Date.now() instead
  };
};

const clickHandler = async () => {
  try {
    const newImg = await getImg(); // wait for getImg() to resolve
    settheimg(newImg); // set img state
    setImgArr((prev) => [...prev, newImg]); // add it to the array
  } catch (err) {
    console.error(err);
  }
};

and in your <button>...

<button onClick={clickHandler}>Search</button>
  • Related