简体   繁体   中英

React: How do I only render a component on the page once I click on it from a mapped array?

I've got a grid of components rendered on a page using the map function and I want to only render the component with all it's details once I click on it and only manage to get an error saying:

Uncaught TypeError: Cannot read properties of undefined (reading 'logo')

I'm new to React and can't figure out why this is happening.

Some help would be much appreciated!

Here's my code:

Body component - (parent component)

 import { useState } from "react"; import CompanyList from "./CompanyList"; import Company from "./Company"; const Body = ({ companies }) => { const [viewCompany, setViewCompany] = useState(false); const showCompanyHandler = (company) => { console.log("Clicked on company card"); setViewCompany(true); }; return ( <div className="appBody"> <CompanyList companies={companies} showCompanyHandler={showCompanyHandler} /> {viewCompany && <Company />} </div> ); }; export default Body;

CompanyList component (child of Body)

 import Company from "./Company"; const CompanyList = ({ companies, showCompanyHandler }) => { return ( <div className="companyList"> {companies.map((company) => ( <Company key={company.id} company={company} showCompanyHandler={showCompanyHandler} /> ))} </div> ); }; export default CompanyList;

Company component (child of CompanyList) - Component I want to display on the page

 const Company = ({ company, showCompanyHandler }) => { return ( <div className="company" onClick={(company) => showCompanyHandler(company)}> {console.log(company)} <img src={company.logo} alt="logo" /> <h1>{company.name}</h1> <p>{company.companyDescription}</p> </div> ); }; export default Company;

I'm not sure what I'm missing here...

If I understood correctly, your code structure is broken and you need to refactor it to implement the kind of logic that you're looking for.

First of all, I would suggest that you remove this {viewCompany && <Company />} , viewCompany and showCompanyHandler from your Body component.

Since the Company component will always be visible, IMO it should be responsible for handling this "expand" logic that you're trying to implement, something like:

 const Company = ({ company }) => { const [showDetails, setShowDetails] = useState(false); const toggleShowDetails = () => setShowDetails(!showDetails); return ( <div className="company" onClick={toggleShowDetails}> {showDetails && <> <img src={company.logo} alt="logo" /> <h1>{company.name}</h1> <p>{company.companyDescription}</p> </> } </div> ); }; export default Company;

As you can see, with this implementation you no longer have to pass showCompanyHandler to the Company component and you can remove all of this logic from the Body component.

If CompanyList component is working fine, an easy way to do it would be to use a function to dynamically generate the list instead of having a direct reference to the component.

import { useState } from "react";
import CompanyList from "./CompanyList";
import Company from "./Company";

const Body = ({ companies }) => {
  const [viewCompany, setViewCompany] = useState(false);

  const showCompanyHandler = () => {
    console.log("Clicked on company card");
    setViewCompany(true);
  };

  // I removed the showCompanyHandler attribute and 
  // added an onClick to CompanyListContainer, instead.
  const generateCompanyList = (companies) => {
    if (viewCompany === false) return null;
    return <CompanyList companies={companies} />
    )
  }

  return (
    <div className="appBody">
      <CompanyListContainer onClick={showCompanyHandler}>
          {generateCompanyList}
      </CompanyList>
    </div>
  );
};

export default Body;

If generateCompanyList is null, there should be nothing to click on, unfortunately. So, you could add some styles to it the div for a minimum width/height, or, you can move that onClick to your appBody component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM