Search code examples
reactjscomponentsstatetogglereact-props

React Toggle Functionality


Current Project Image

I have a Content component that renders 2 Panel components. The Content component passes its state to panel 1 and passes !state to panel 2. (Panel 1 is initially visible and panel 2 is not)

Desired Functionality:

  • When the user clicks the "hidden" component, it sets it to visible and hides the visible one.
  • If the user clicks the now visible component, nothing happens but if the now hidden component is clicked, it should become visible and the visible one goes back to being hidden.

Content.jsx

import React, { useState } from "react";
import Panel from "../panel/Panel";
import "./content.styles.css";

const Content = ({ selected, panelA, panelB }) => {
  const [active, setActive] = useState(true);

  return (
    <div className={`content-wrapper ${selected ? "visible" : "hidden"}`}>
      <Panel active={active} panelText={panelA} setActive={setActive} />
      <Panel active={!active} panelText={panelB} setActive={setActive} />
    </div>
  );
};

export default Content;

Panel.jsx

import React from "react";
import "./panel.styles.css";

const Panel = ({ panelText, active, setActive }) => {
  const handleClick = () => {
    if(!active){
      setActive(false);
    }
  };


  return (
    <div
      onClick={handleClick}
      className={`panel-wrapper ${
        active ? "active-component" : "hidden-component"
      }`}
    >
      {panelText}
    </div>
  );
};

export default Panel;

I really hope I'm just missing something or I'm not understanding how React is working under the hood. I really appreciate any help or advice you could give me to get me going down the right path.

Thank you so much!


Solution

  • If I understood your question correctly, this codesandbox that I created should help.

    Issues

    You are almost there, but you have a couple of issues here:

    1. Using only one state variable for both child components.

    Since you are setting active to true and false, and passing the same state variable to both panels, panels will affect each other.

    1. Setting active to false if panel isn't active
     const handleClick = () => {
        if(!active){
          setActive(false); // If the panel is not active, no reason to setActive(false)
        }
      };
    

    Solution

    1. You need to have separate identifiers for panels, that is why I used an array to keep track of active panels (if you have only two a string will also be fine)
    const [activePanels, setActivePanels] = useState([/* initial active panels */])
    
    1. You can add and remove to this array based on your panel's condition:
      const handleClick = () => {
        if (!active) setActivePanels([panelText]);
      };