Search code examples
javascriptreactjstypescriptreact-bootstrapreact-modal

How to trigger API inside React Modal only when Modal is opened?


I am working on a REACT based web-app POC in my org. There is table of issues and for each of these issues, I have to provide a button in the table which when a user clicks on - it will open up a modal, fetch data for that issue via an API call and then broadcast the data in that modal.

The problem: Let's say I have 300 issues listed in that table, hence there are 300 clickable buttons for opening modals and calling API. Now the problem is that, whenever that table loads, it calls APIs for all 300 issues at once, but I want each API to only be called when an user clicks on the respective button!

Here is the code for Modal component which I have managed so far:

import React, { FunctionComponent, useState, useEffect } from 'react'; // importing FunctionComponent
import { Modal, Button } from 'react-bootstrap';

type IssueReportProps = {
    issueInfo: any
}

const IssueReport: FunctionComponent<IssueReportProps> = ({ issueInfo }) => {
    const issueNumber: string = issueInfo.number;
    const [show, setShow] = useState(false);
    const [diagnosisInfo, setdiagnosisInfo] = useState({});
    const handleClose = () => setShow(false);
    const handleShow = () => setShow(true);
    
    useEffect(() => {
        async function fetchData() {
            const res = await fetch("http://api-call/?issuenumber=".concat(issueNumber));
            res.json().then(res => setdiagnosisInfo(res));
        }
        fetchData();
    }, [issueNumber]);

    console.log(diagnosisInfo);
    return (
        <>
            <Button variant="outline-primary" onClick={handleShow} size="sm">
                Diagnosis
            </Button>

            <Modal show={show} onHide={handleClose} backdrop="static" keyboard={false}>
                <Modal.Body>
                    <p>
                        Issue Info: {JSON.stringify(diagnosisInfo)}
                    </p>
                </Modal.Body>

                <Modal.Footer>
                    <Button variant="secondary" onClick={handleClose}>Close</Button>
                </Modal.Footer>
            </Modal>
        </>
    );
};

export default IssueReport;

The console.log(diagnosisInfo); confirms my suspicions that once the issue is loaded, APIs for all issues are called. How to prevent this? Please let me know if I need to provide more details.

EDIT1: Accepted Solution-

Here is the change I made to the code post @Dykotomee's solution:

// useEffect:
    useEffect(() => {
        async function fetchData() {
            const res = await fetch("http://api-call/?issuenumber=".concat(issueNumber));
            res.json().then(res => setdiagnosisInfo(res));
        }
        // fetchData();
        if (show){
            fetchData();
        }
    }, [issueNumber, show]);

Solution

  • useEffect is called every time the component renders. Therefore, when the table loads with 300 components, the API is fetched 300 times!

    You only want to fetch if the modal is showing. Try wrapping your call to fetchData in a conditional:

    if (show) {
        fetchData();
    }
    

    It's not ideal, considering the modal will likely show prior to the fetch being completed, but you can adjust your code or add more states to compensate.