Home > Mobile >  React not updating state?
React not updating state?

Time:08-10

I´m new to react. I´m trying to fetch an endpoints array. and I want to update the api's status every 15 seconds. I´m trying to do this

const [data, setData] = useState<Response[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<string[] | null[]>([]);

const effectRan = useRef(false);

  const fetching = async () => {
    setLoading(true);
    endpoints.map(async (endpoint) => {
      return await axios
        .get(endpoint)
        .then((res) => {
          setData((prev) => [...prev, res.data]);
        })
        .catch((err) => {
          setError([...error, err.message]);
        });
    });
    setLoading(false);
  };

  useEffect(() => {
    if (!effectRan.current) {
      fetching();
    }
    return () => {
      effectRan.current = true;
    };
  });

  useEffect(() => {
    setTimeout(async () => {
      setData([]);
      setLoading(true);
      setError([]);

      await fetching();
    }, 15000);
  }, []);

but when the seTimeout runs every card duplicates and the state gets more data than before. even though I´m reseting the state to setData([]) I just want to update the api's status. What can i do?

This is the rest of my code

if (loading) return <Spinner />;
  return (
    <div className="card-container">
      {data.length ? (
        data.map((item) => {
          return (
            <Card
              key={generateKey()}
              hostname={item.hostname}
              message={item.message}
              success={item.success}
              time={item.time}
            />
          );
        })
      ) : (
        <Spinner />
      )}
      {error.length
        ? error.map((err) => (
            <ErrorCard key={generateKey()} message={err as string} />
          ))
        : null}
    </div>
    ```

CodePudding user response:

I think this piece of code might be adding additional data instead of overwriting the existing one. Is that what you're trying to do?

setData((prev) => [...prev, res.data]);

CodePudding user response:

Theres a few things wrong here and one or more probably fixes it:

  • You keep a ref around to track the first fetch but theres no need as you can do that by virtue of using [] in an effects deps array, which you already have.
  • The loading state does not wait until all requests in flight finished.
  • The 15 second interval does not wait until all requests launched are finished.
  • You dont clear down the timer if the component unmounts and remounts.

Your code, by design it seems, does append data each time one of the requests comes back -- but I think that was intentional?

  const [data, setData] = useState<Response[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<string[] | null[]>([]);

  const fetching = async () => {
    setLoading(true);
    await Promise.all(
      endpoints.map((endpoint) => {
        return axios
          .get(endpoint)
          .then((res) => {
            setData((prev) => [...prev, res.data]);
          })
          .catch((err) => {
            setError([...error, err.message]);
          });
      })
    );
    setLoading(false);
  };

  useEffect(() => {
    let timer: number | null = null;
    const intervalFetch = async () => {
      await fetching();
      timer = setTimeout(async () => {
        setError([]);
        setData([]);
        intervalFetch();
      }, 15000);
    };

    intervalFetch();

    return () => timer !== null && clearTimeout(timer);
  }, []);
  • Related