skip to Main Content

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.

3

Answers


  1. 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.

    Login or Signup to reply.
  2. 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/[email protected]/umd/material-ui.development.js"></script>
    Login or Signup to reply.
  3. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search