0

I do not understand why this code is an infinit loop. I this it is because I update my state in else if condition. But i'd like to update an array of urls when getting new api answer.

import React, { useState, useEffect } from 'react';

function getShortenUrl() {
  const [urls, setUrls] = useState([])
  const [error, setError] = useState(null);
  const [items, setItems] = useState({});

  useEffect(() => {
    fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
      .then(res => res.json())
      .then(
        (result) => {
          setItems(result);
        },
        (error) => {
          setError(error);
        }
      )
  }, [])

  if (error) {
    return <div>Error : {error.message}</div>;
  } else if (!items.result) {
    return <div>Loading...</div>;
    console.log("no item");
  } else {
    setUrls([urls, items]);
    console.log("items", items);
    console.log("urls", urls);
    return <ul> {items.result.short_link}</ul>;
  }
}


export default getShortenUrl;

I am kindof lost when it comes to state actually. I do not understand how I can create an array of urls and be able to use it in other components.

Mmmmmh
  • 3
  • 1
  • You shouldn't have individual return statements: instead, have one single return statement and use if/else logic inside the return statement instead for conditional rendering. – Terry Feb 22 '22 at 09:43

3 Answers3

1

You may have some mistakes here

      .then(
        (result) => {
          setItems(result);
        },
        (error) => {
          setError(error);
        }
      )

Change it into

.then((result) => {
          setItems(result);
          setUrls([...urls, result])
})
.catch((error) => {
          setError(error);
})

And also remove the line setUrls([urls, items]);

Huan Le
  • 206
  • 2
  • 5
  • Hey, thank you for your answer. How do I use the returned short_link to fill an array in an other component ? – Mmmmmh Feb 22 '22 at 10:29
  • With this case, you should create and use `useContext` vs `dispatch`. Check it out with this guide and example here: https://kentcdodds.com/blog/how-to-use-react-context-effectively – Huan Le Feb 22 '22 at 10:33
0

Try to use a conditional rendering instead of if else statement:

import React, { useState, useEffect } from 'react';

function getShortenUrl() {
  const [urls, setUrls] = useState([])
  const [error, setError] = useState(null);
  const [items, setItems] = useState({});

  useEffect(() => {
    fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
      .then(res => res.json())
      .then(
        (result) => {
          setItems(result);
        },
        (error) => {
          setError(error);
        }
      )
  }, [])

return (

         <>
             {error&& <div>Error : {error.message}</div>}
             {!items.result && <div>Loading...</div> }
             {items.result &&  <ul> {items.result.short_link}</ul>}
        </>
   )
 
}


export default getShortenUrl;

Giovanni Esposito
  • 10,696
  • 1
  • 14
  • 30
Vida Hedayati
  • 328
  • 1
  • 7
  • Hey, thank you for your answer. How do I use the returned short_link to fill an array in an other component ? – Mmmmmh Feb 22 '22 at 09:57
0

If you are new to react then we make Loading state for API Call fetch and you are setting state in else and when state updates component re-renders so on every component re-render you are updating state which is causing infinite loop. Try this

import React, { useState, useEffect } from 'react';

function getShortenUrl() {
  const [urls, setUrls] = useState([])
  const [error, setError] = useState(null);
  // const [items, setItems] = useState({}); // remove it because you are using urls and items state for same purposes
  const [loading,setLoading]=useState(false);

  useEffect(() => {
    setLoading(true);
    fetch("https://api.shrtco.de/v2/shorten?url=https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array")
      .then(res => res.json())
      .then(
    (result) => {
      // setItems(result); // remove it
      setUrls(result);
      setLoading(false);
    },
    (error) => {
      setError(error);
      setLoading(false);
    }
      )
  }, [])
      if(loading){
           return <div>Loading...</div>;
      }
  if (error) {
    return <div>Error : {error.message}</div>;
  } else {
    return <ul> {urls?.result?.short_link}</ul>;
  }
}


export default getShortenUrl;
Asad Haroon
  • 476
  • 3
  • 9
  • Hey, thank you for your answer. How do I use the returned short_link to fill an array in an other component ? – Mmmmmh Feb 22 '22 at 09:57
  • You can store it globally either using Context or Redux to avoid props drilling. And you can also send to child component via props. like – Asad Haroon Feb 22 '22 at 10:55