Ana
Ana

Reputation: 167

Avoid infinite loop with useEffect hook

I am trying to display an updated list of items every time a new item is added using the form. Using the useEffect hook I keep getting stuck in an infinite loop that crashes the page. I am not sure how to add some sort of validation that ask to re-render my component only if a new item has been added.

@app.route('/assets')
def get_assets():
  print('this is a test')
  cursor = assets.find() 
  list_cur = list(cursor)
  assets = dumps(list_cur)
  return assets

 function Assets() {
  const [currentAsset, setCurrentAsset] = useState(0);

  useEffect(() => {
    (async () => {
      const result = await fetch('/assets')
      const data = await result.json()
      setCurrentAsset(data)
    })()
  }, [currentAsset]);
 
 
  return (
    <div>
      <header>
      <table className="table table-striped">
        <thead>
          <tr>
            <th>Ip Address</th>
            <th>Asset Type</th>
            <th>Username</th>
            <th>Notes</th>
          </tr>
        </thead>
        <tbody>
        {Object.values(currentAsset).map((item, index) => (
          <tr key={item._id? item._id.$oid: null}>
            <td>{item.ip_address}</td>
            <td>{item.asset_type}</td>
            <td>{item.username}</td>
            <td>{item.notes}</td>
          </tr>
          )
        )}
        </tbody>
      </table>
      </header>
    </div>
  );

}

export default Assets;

NOTE: I would like to renders updating data without reloading the page every time a new item has been added. I am trying to achieve the same result as this demo: https://taniarascia.github.io/react-hooks/ Is there a Hooks only approach to this?

Upvotes: 0

Views: 387

Answers (3)

XXLIVE
XXLIVE

Reputation: 156

Usually, queries make items change, we should listen changes of query, and update items. just add a query state to make logic clear.


function Assets() {
  const [currentAsset, setCurrentAsset] = useState({});
  const [query, setQuery] = useState('');

  useEffect(() => {
    (async () => {
      const result = await fetch('/assets?query=' + query)
      const data = await result.json()
      setCurrentAsset(data)
    })()
  }, [query]);
 
  return (
    <div>
      <header>
      <table className="table table-striped">
        <thead>
          <tr>
            <th>Ip Address</th>
            <th>Asset Type</th>
            <th>Username</th>
            <th>Notes</th>
          </tr>
        </thead>
        <tbody>
        {Object.values(currentAsset).map((item, index) => (
          <tr key={item._id? item._id.$oid: null}>
            <td>{item.ip_address}</td>
            <td>{item.asset_type}</td>
            <td>{item.username}</td>
            <td>{item.notes}</td>
          </tr>
          )
        )}
        </tbody>
      </table>
      </header>
    </div>
  );

}

export default Assets;

Upvotes: 0

IamMHC
IamMHC

Reputation: 86

Inside the “useEffect”, it will update the state “currentAsset”. Then it will trigger the component to re-render again. As a result, “useEffect()” will run again and update the state. Next, the whole process repeats again, and you're trapped inside an infinite loop.

 useEffect(() => {
    (async () => {
      const result = await fetch('/assets')
      const data = await result.json()
      setCurrentAsset(data)
    })()
  }, []);

Upvotes: 1

Khaled Ahmed
Khaled Ahmed

Reputation: 1134

You can't update state variable that in the dependancies for useEffect inside it you can make multiple useEffects you should retrieve it first in empty useEffect then make another one to listen on currentAsset change

useEffect(() => {
    /// this will work as componentDidMount 
   // will be called only once at the first after rendering the component
    (async () => {
     const result = await fetch('/assets')
     const data = await result.json()
     setCurrentAsset(data)
   })()
 }, []);

 useEffect(() => {
    // listen on the change of the currentAsset here but DONOT update it here
 }, [currentAsset]);

Upvotes: 0

Related Questions