0

I can make sure "console.log("client.ImageNames", client.ImageNames);" works and get the result like below. client.ImageNames

  • (3) [“image1.png", "image2.png", "image3.png"]
    • 0: "image1.png"
1: "image2.png"
2: "image3.png"
length: 3
proto: Array(0)

However, when I tried to loop the array, it worked first, but when I reloaded, I got "Cannot read property 'forEach' of undefined". I guess useEffect hook is related to this issue but I have no idea how to fix it.

import { useParams } from "react-router-dom";
import React, { useState, useEffect } from "react";
import axios from "axios";

const ClientDetail = () => {
  const { id } = useParams();
  const [client, setClients] = useState({});


  useEffect(() => {
    axios.get(`http://localhost:8080/clients/${id}`).then((response) => {
      setClients(response.data);
    });
  }, []);

  useEffect(() => {
    setClients(client);

    console.log("client.ImageNames", client.ImageNames);

    client.ImageNames.forEach((element) => {
      console.log("element : " + element);
    });
  }, [client]);

  return (
    <div>
      {client.name}
    </div>
  );
};

export default ClientDetail;
jimi1206
  • 1
  • 3
  • 1
    That effect is only called once, so what do you mean with "when useEffect is called twice". – Andy Jun 26 '21 at 08:06
  • Yes useEffect is called only once. But let's say when you reload a page and do http request again, you can make sure that the response is returned by checking console.log(response.data), but console.log("client", client) prints empty so I assume setClients doesn't work properly. – jimi1206 Jun 26 '21 at 08:25
  • You have passed the second argument to `useEffect` hook as `[ ]`, which wouldn't execute the hook more than once. Or you can say your implementation of `useEffect` will only execute much like ComponentDidMount( ) – jateen Jun 26 '21 at 08:25
  • 1
    `setClients` is an async process so you can't immediately log it to the console. Add another effect to test this: `useEffect(() => console.log(client), [client])` – Andy Jun 26 '21 at 08:29
  • 1
    React state updates are asynchronously processed, the updater functions ***are not*** `async` though. When you console log the state *right* after enqueueing an update you are logging the state value from the ***current*** render cycle, not what it will be for the ***next*** render cycle. Use an `useEffect` hook with appropriate dependency to log state updates. – Drew Reese Jun 26 '21 at 08:34
  • Thank you guys, I faced a new problem so I appreciate it if you can help me with that. – jimi1206 Jun 27 '21 at 08:34
  • Initial value of `client` state value is an empty object (`{}`), so `client.ImageNames` is undefined, and thus `client.ImageNames.forEach` throws error. You can use optional chaining to guard against null/undefined values `client.ImageNames?.forEach`. – Drew Reese Jun 27 '21 at 19:27
  • @DrewReese Thank you I understand. I found out that as you said the updater functions are not async, before setClients is called, client.ImageNames.forEach. So I made sure "client.ImageNames.forEach" was called as 'undefined' thanks to the optional chaining. But is it possible to make the updater functions asynchronously process? If so I think client.ImageNames can be called after setClients is finished. – jimi1206 Jun 28 '21 at 10:20
  • No, this isn't how React state updates work. Your second `useEffect` may also have an issue, it calls `setClients(client);` ***and*** specifies `client` as a dependency, this is likely to cause render looping. If you are only trying to log the state value then just remove the state update and use the null-check on `client.ImageNames` when looping over the state. – Drew Reese Jun 28 '21 at 16:24

0 Answers0