How to open React Material-UI modal and populate with Ajax call upon clicking button?

Tried to search for a similar question but couldn’t find any, apologies if I missed one. I am using React Material-UI to create a simple web application. I have an XGrid which lists a number of products and various statistics over a user-selected date range. Each row has a button that the user can click. The idea is that, upon clicking the button, the application calls an API to get relevant information about the product in that row. I would like the info returned from the API to be displayed on a Material-UI modal.

I am getting stuck on how to pass the information from the API to the Modal component and display it. I have a simple example in the code below that is close to what I want to accomplish.

import "./styles.css";
import React from "react";
import { Button, Modal, Typography, Box } from "@material-ui/core";

export default function App() {
  const [open, setOpen] = React.useState(false);
  const handleClose = () => setOpen(false);
  
  return (
    <div className="App">
      <Button
        variant="outlined"
        color="primary"
        onClick={() => {
          setOpen(true);
          (async () => {
            let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
            let apiCall = await response.json();
            let grouped_data = JSON.parse(apiCall.data);
          })();
        }}
      >
        Click Here
      </Button>
      <Modal open={open} onClose={handleClose}>
        <Box>
          <Typography>Random Text</Typography>
        </Box>
      </Modal>
    </div>
  );
}

In this example, I isolated the code into one single App.js on codesandbox. However, in practice I would have the Button and Modal combined into a separate component file with the API URL passed as a prop to the component. I also used JSONPlaceholder instead of my actual API. Currently, the button displays a modal which says “Random Text”. However, I would like it to display the information retrieved using the fetch call.

Also, the table will have thousands of rows so I would like to avoid calling the API until the user actually clicks the button. That way I don’t overload the server with thousands of separate API calls every time someone loads the page. I appreciate any help anyone could provide.

Answer

You would be better to create a variable to hold the information retrieved from the api, and a common function which would be called from the button click. Something like this:

import "./styles.css";
import React from "react";
import { Button, Modal, Typography, Box } from "@material-ui/core";

export default function App() {
  const [open, setOpen] = React.useState(false);
  const [data, setData] = React.useState(null);

  const handleClose = () => {
    setOpen(false);
    setData(null);
  };

  const getData = async (someID) => {
    try {
      let response = await fetch(
        `https://jsonplaceholder.typicode.com/todos/${someID}`
      );
      let apiCall = await response.json();
      let grouped_data = JSON.parse(apiCall.data);
      setOpen(true);
      setData(grouped_data);
    } catch (error) {
      //Handle errors
    }
  };

  return (
    <div className="App">
      <Button
        variant="outlined"
        color="primary"
        onClick={() => {
          getData(someID);
        }}
      >
        Click Here
      </Button>
      <Modal open={open} onClose={handleClose}>
        <Box>
          <Typography>{data ? data.some_property : ''}</Typography>
        </Box>
      </Modal>
    </div>
  );
}