Home > Mobile >  How to Create Show/Hide button when Looping in React
How to Create Show/Hide button when Looping in React

Time:01-20

I am working on a development site and am having an issue. The issue is that I am looping over the data file in order to create some project cards. Each project card has a show more/show less button to display/hide card descriptions.

My problem is that the current setup is mapping over the data and causing it so that whenever one gets clicked, all three either open or close simultaneously. Please help me to fix this issue. Relevant code is shown below:

Data example:

{
name: "Hot in the Biscuit",
id: "3a34",
image: "/images/bonnie.jpg",
description: "A multi-page front-end business website for a local restaurant in Koh Samui, Thailand. Custom design built with vanilla JavaScript, HTML and CSS.",
link: "https://www.xxxxxxxxxxxxx.com",
date: "2021",
github: "https://github.com/xxxxxxxxxxxxxxxxxxxxxx"
},

Hero file where Showcase Component is rendered:

               <h1>Featured Projects</h1>
             <div>
             <Showcase/>
             </div>

Showcase where cards are created (UNNECCESSARY CODE REMOVED - classes and image):

const Showcase = () => {
    const {readMore, setReadMore} = useContext(HeroContext)
    const {toggleMenu} = useContext(NavbarContext)
    return(
        <>
  {showcase.map((item) => {
    const {id, name, image, link, github, description, date} = item;
      return (
        <div key={id}>
        <div>
       {!toggleMenu &&
        <div>
        <Image/>
        </div>
       }
        </div>
        <div>
            <div>
                <h2>{name} | {date}</h2>
            </div>
            <div>
                <h4>{ readMore ?
                    description :
                    `${description.substring(0, 100)}...`
                    } <button key={id} onClick={() => setReadMore(!readMore)}>{readMore ? "Show Less" : "Show More"}</button>
                    </h4>
            </div>
            <div>
            <a href={github}>
                <FiGithub/>
            </a>
                <a href={link}>
                <h4 >See For Yourself! &#8594;</h4>
                </a>
            </div>
        </div>
    </div>
      )
  })}   
  </>
    )   
}
export default Showcase
           

So I just need some help on figuring out how to set it up so that each button knows which card is being clicked and only that button open. Thank you very much for helping me. I appreciate your time and help immensely.

Bodi

CodePudding user response:

You should update the HeroContext state to hold a reference to the ids that are shown/hidden.

Example:

const [readMoreState, setReadMoreState] = useState({});

const readMore = (id) => setReadMoreState(state => ({
  ...state,
  [id]: !state[id], // <-- toggle boolean value
}));

// context value
{ readmore: readMoreState, setReadMore }

...

const { readMore, setReadMore } = useContext(HeroContext);

...

{showcase.map((item) => {
  const {id, name, image, link, github, description, date} = item;
  return (
    <div key={id}>
      <div>
        ...
      </div>
      <div>
        ...
        <div>
          <h4>
            {readMore
              ? description
              : `${description.substring(0, 100)}...`
            }
            <button
              onClick={() => setReadMore(id)} // <-- pass id to toggle
            >
              {readMore[id] ? "Show Less" : "Show More"} // <-- check by id if toggled true|false
            </button>
          </h4>
        </div>
      <div>
      ...
    </div>
  )
})}  

CodePudding user response:

It will be easier if you split showcase item to a new component.

const ShowCaseItem = ({ data }) => {
  const { toggleMenu } = useContext(NavbarContext)
  const [readMore, setReadMore] = useState(false)
  const { id, name, image, link, github, description, date } = data;
  return (
    <div key={id}>
      <div>
        {!toggleMenu &&
          <div>
            <Image />
          </div>
        }
      </div>
      <div>
        <div>
          <h2>{name} | {date}</h2>
        </div>
        <div>
          <h4>{readMore ?
            description :
            `${description.substring(0, 100)}...`
          } <button key={id} onClick={() => setReadMore(!readMore)}>{readMore ? "Show Less" : "Show More"}</button>
          </h4>
        </div>
        <div>
          <a href={github}>
            <FiGithub />
          </a>
          <a href={link}>
            <h4 >See For Yourself! &#8594;</h4>
          </a>
        </div>
      </div>
    </div>
  )
}
const Showcase = () => {
  const { readMore, setReadMore } = useContext(HeroContext)
  return (
    <>
      {showcase.map((item) => <ShowCaseItem data={item} />)}
    </>
  )
}
export default Showcase
  •  Tags:  
  • Related