Skip to content
Advertisement

How to use useEffect and for loop to generate multiple JSX elements

I want to use useEffect and for-loop to generate multiple JSX elements but nothing is rendered in this case.

warning code: “React Hook useEffect has a missing dependency: ‘renderInfoCard’. Either include it or remove the dependency array react-hooks/exhaustive-deps”

import React, { useState, useEffect } from 'react';
import InfoCard from '../components/InfoCard.jsx';
import { getScenicSpotRequest } from '../request test.js';

function MainScreen() {

  const [renderInfoCard, setRenderInfoCard] = useState(null);
  const [renderInfoCardArray, setRenderInfoCardArray] = useState([]);

  useEffect(() => {
    //data recieve from axios request
    getScenicSpotRequest().then(result => {
    //want to use useEffect and for loop to generate multiple JSX elements 
      for (let i = 0; i < result.length; i++) {
        setRenderInfoCard(<InfoCard Name={result[i].Name} Description={result[i].Description} Picture={result[i].Picture.PictureUrl1} />);
        setRenderInfoCardArray[i] += renderInfoCard;
      }
    });
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <Navbar NavbarTitle="ScenicSpot" />
        {renderInfoCardArray}
      </header>
    </div>
  );
}

export default MainScreen;

Advertisement

Answer

I wouldn’t put components in state (and you really shouldn’t mutate state either). Instead, wait for all the results to come back, then set the state with all of the results at once. When returning the JSX, then you can create the components by mapping over the results (if they exist).

function MainScreen() {
  const [sceneResults, setSceneResults] = useState([]);
  useEffect(() => {
    getScenicSpotRequest()
      .then(setSceneResults);
      // .catch(handleErrors); // don't forget this - don't want unhandled rejections
  }, [setSceneResults]); // this will not change, so it's safe to put in the dependency array
  return (
    <div className="App">
      <header className="App-header">
        <Navbar NavbarTitle="ScenicSpot" />
        {sceneResults.map(result => (
          <InfoCard Name={result.Name} Description={result.Description} Picture={result.Picture.PictureUrl1} />)
        )}
      </header>
    </div>
  );
}

I put the setSceneResults into the effect dependency array to satisfy the linter, but that’s OK, the reference to the state setter is stable, so it’ll only run on mount.

Advertisement