'Message prints in every Dynamic Accordion in ReactJs

I have a dynamic Accordion in ReactJs. I am getting the message from my backend. but it's printing in every Accordion. I'm sharing the code

import React, { useState, useEffect } from "react";

import ApplicantDash from "./ApplicantDash";
import {
  Accordion,
  AccordionSummary,
  AccordionDetails,
  Typography,
} from "@material-ui/core";
import * as FcIcons from "react-icons/fc";

import ApplicantService from "../services/ApplicantService";

export default function AvailJobs() {
  const [aplcntEmail, setAplcntEmail] = useState("[email protected]"); //change to aplcntemail
  const [isShow, setIsShow] = useState(false);
  const [msg, setMsg] = useState([""]);
  const [job, setJob] = useState([
    {
      jobTitle: "",
      dateOfPosting: Date,
      lastDateToApply: new Date().toLocaleDateString([], {
        year: "numeric",
        month: "long",
        day: "numeric",
      }),
      preferableSkills: [],
      requiredExp: 0,
      recruiterEmail: "",
      companyName: "",
      companyAddress: "",
      
    },
  ]);

  useEffect(() => {
    const data = ApplicantService.getAllJobs()
      .then((response) => {
        console.log(response.data);
        setJob(response.data);
      })
      .catch((error) => {
        alert(error.response.data);
      });
  }, []);

  const onApplyButton = (item,key) => {
     const data2 = ApplicantService.applyForJob(aplcntEmail, item)
      .then((response) => {
        console.log(response.data);
        setIsShow(true);
        setMsg(response.data)
    
      })
      .catch((error) => {
        setIsShow(true);
        setMsg(error.response.data);
        
      });
  };
  return (
    <div>
      <ApplicantDash />
      <div className="container bg-light">
        <div className="card-bodies">
          <section className="mb-4">
            <h2 className="h1-responsive font-weight-bold text-center my-4">
              All Available jobs
            </h2>
          </section>
          {job.map((item, key) => (
            <>
            
              <Accordion key={key}>
                <AccordionSummary
                  expandIcon={<FcIcons.FcExpand />}
                  aria-controls="panel1a-content"
                  id="panel1a-header"
                  className="Accordian"
                >
                  <Typography>
                    <div className="d-flex p-1 justify-content-evenly">
                      <div className="p-1">
                        <b> Job: </b> {item.jobTitle}
                      </div>
                      <div className="p-2"></div>
                      <div className="p-1">
                        <b> Company: </b> {item.companyName}
                      </div>
                      <div className="p-2"></div>
                      <div className="p-1">
                        <b> Last Date: </b> {item.lastDateToApply}
                      </div>
                    </div>
                  </Typography>
                </AccordionSummary>
                <AccordionDetails>
                  <Typography>
                    <div className="container">
                      <table class="table table-borderless">
                        <tbody>
                          <tr>
                            <td>JOB TITLE</td>
                            <td>:</td>
                            <td>
                              <b>{item.jobTitle}</b>
                            </td>
                          </tr>
                          <tr>
                            <td>Company</td>
                            <td>:</td>
                            <td>
                              <b>{item.companyName}</b>
                            </td>
                          </tr>
                          <tr>
                            <td>Address</td>
                            <td>:</td>
                            <td>
                              <b>{item.companyAddress}</b>
                            </td>
                          </tr>
                          <tr>
                            <td>Last Date to Apply</td>
                            <td>:</td>
                            <td>
                              <b>{item.lastDateToApply}</b>
                            </td>
                          </tr>
                          <tr>
                            <td>Experience</td>
                            <td>:</td>
                            <td>
                              <b>{item.requiredExp}</b>
                            </td>
                          </tr>
                          <tr>
                            <td> Skills </td>
                            <td>:</td>
                            <td>
                              <table className="table table-condensed w-auto table-borderless table-hover">
                                {item.preferableSkills.map((S, index1) => {
                                  return (
                                    <tbody key={index1}>
                                      <td scope="col">
                                        {index1 + 1}.<b>{S}</b>
                                      </td>
                                    </tbody>
                                  );
                                })}
                              </table>
                            </td>
                          </tr>
                          <tr>
                            <td></td>
                            <td></td>
                            <td>
                              <button
                                type="button"
                                class="btn btn-primary"
                                onClick={() => onApplyButton(item,key)}
                              >
                                Apply for the job{" "}
                              </button>
                            </td>
                          </tr>
                        </tbody>
                          {isShow && <> 
                            {msg}
                         </>}
                      </table>
                    </div>
                  </Typography>
                </AccordionDetails>
              </Accordion>
            </>
          ))}
        </div>
      </div>
    </div>
  );
}

Now when I click on Apply for this job button. The message I get from backend prints only to Active accordion Here some pictures which might help.

enter image description here

As you can see the response from backend is prints in the both of the accordion



Solution 1:[1]

Issue

The issue here is that you've a single boolean isShow state and a single msg state, and all the accordion detail sections use the same single isShow state to conditionally render the msg state.

Solution

A simple solution would be to store the id, or title, or index, of the accordion to show the message of.

Example:

export default function AvailJobs() {
  ...

  const [isShow, setIsShow] = useState({}); // <-- initially empty object

  ...

  const onApplyButton = (item, key) => {
    ApplicantService.applyForJob(aplcntEmail, item)
      .then((response) => {
        console.log(response.data);
        setMsg(response.data);
      })
      .catch((error) => {
        setMsg(error.response.data);
      })
      .finally(() => {
        setIsShow(show => ({
          ...show,
          [key]: true // <-- set true the specific key
        }));
      });
  };

  return (
    <div>
      ...
          {job.map((item, key) => (
            <Accordion key={key}>
              ...
              <AccordionDetails>
                <Typography>
                  <div className="container">
                    <table class="table table-borderless">
                      <tbody>
                        ...
                        <tr>
                          ...
                          <td>
                            <button
                              type="button"
                              class="btn btn-primary"
                              onClick={() => onApplyButton(item, key)}
                            >
                              Apply for the job
                            </button>
                          </td>
                        </tr>
                      </tbody>
                      {isShow[key] && <>{msg}</>} // <-- check if isShow[key] is truthy
                    </table>
                  </div>
                </Typography>
              </AccordionDetails>
            </Accordion>
          ))}
      ...
    </div>
  );
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1