0

How would I go about creating a component using useEffect?

useEffect(() => {
      fetch('https://website')
         .then((res) => res.json())
         .then((data) => {
            setData(data)

            // Use fetched data to create object "roles"

            let cards = roles.map((path) => (
               <Box m="sm" pt="xl">
                  <Card key={path.id} p="lg" radius="md href="#"
                     onClick={ () => handlePopup(path.role) }>
                  </Card>
               </Box>
            ));
      })
}

return (
    <>
       {cards} // this doesn't work.
    </>

)

Current code is not working. "cards" is not loading, just getting a blank area. I'm keeping it all in the fetch because the data is dependent and I"m not sure how to split it up. Not sure if there's a smarter way.

Lewis
  • 135
  • 1
  • 10

3 Answers3

3

You can map over your state variable outside the useEffect

useEffect(() => {
  fetch('https://website')
    .then((res) => res.json())
    .then((data) => {
      setData(data)
    })
}

return (
  <>
    {data.roles.map((path, i) => (
      <Box key={i} m="sm" pt="xl">
        <Card key={path.id} p="lg" radius="md href="#"
          onClick={ () => handlePopup(path.role) }>
        </Card>
      </Box>
    ));}
  </>
)

If you want to store them in a separate variable, you can set it outside the useEffect so that it is accessible.

useEffect(() => {
  fetch('https://website')
    .then((res) => res.json())
    .then((data) => {
      setData(data)
    })
}

const cards = data.roles.map((path, i) => (
  <Box key={i} m="sm" pt="xl">
    <Card key={path.id} p="lg" radius="md href="#"
      onClick={ () => handlePopup(path.role) }>
    </Card>
  </Box>
));

return (
  <>
    {cards}
  </>
)

As mentioned in the comments, you also need to set a unique key when mapping elements.

axtcknj
  • 367
  • 1
  • 9
1

You should store (useState) the raw JS object array (result) from the fetch call separate from constructing the rendered DOM.

A key should go on each direct element of the Array.prototype.map call. In the example below, the <Grid> wrapper receives this prop.

Note: Since the role associated with the id can possibly change over time, the id or even an index may not be unique enough. You could hash the object to receive a truly unique ID, or you can generate a UUID.

const { useCallback, useEffect, useState } = React;
const { Box, Card, CardContent, Container, Grid } = MaterialUI;

// https://stackoverflow.com/a/2117523/1762224
const uuidv4 = () =>
  ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16));

const randomUUID = () => {
  try { return crypto.randomUUID(); } // Should be fine...
  catch (e) { console.log('Session is insecure'); return uuidv4(); }
}

const fetchPaths = () => Promise.resolve([
  { id: 1, role: 'admin' },
  { id: 2, role: 'user' }
]);

const App = () => {
  const [paths, setPaths] = useState([]);

  useEffect(() => {
    fetchPaths().then(setPaths); // Store the result
  }, []);

  const handlePopup = useCallback((role) => {
    alert(role);
  }, []);

  return (
    <Container>
      <Grid container spacing={2}>
        {paths.map(path => (
          <Grid key={randomUUID()} item xs={6}>
            <Box m="sm" pt="xl">
              <Card
                p="lg"
                radius="md"
                href="#"
                onClick={() => handlePopup(path.role)}>
                 <CardContent>
                  {path.role}
                 </CardContent>
              </Card>
            </Box>
          </Grid>
        ))}
      </Grid>
    </Container>
  );
};

ReactDOM
  .createRoot(document.getElementById('root'))
  .render(<App />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@material-ui/core@4.7.2/umd/material-ui.development.js"></script>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

the best idea in this case is to fetch data outside the useeffect ..then use usestate to create the cards componenet ..use [data] as a variable that useeffect depend on to change or observe

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 26 '23 at 23:02