skip to Main Content

I have created a component and am using useState to update an area of it where it expands when a button is clicked. When I map multiple instances of this component and click the expand button on one of them, all of them expand. How do I fix this?

Here is my code:

const ContainerMenu: React.FC<ContainerMenuProps> = (props: ContainerMenuProps) => {
    const [expanded, setExpanded] = useState(false);

    return (
        <>
            <div className={`docker-container-menu ${expanded}`}>
                <button onClick={() => setExpanded(!expanded)} className='chevron-button'>
                    <Icon path={mdiChevronDown} size={1} />
                </button>
                {expanded && <div className='docker-container-menu-expanded'>
                    <button style={{ cursor: "pointer" }} onClick={() => props.startContainer(props.Id)}>
                        <Icon style={{color: "green"}} path={mdiPlay} size={1} />
                    </button>
                    <button style={{ cursor: "pointer" }} onClick={() => props.stopContainer(props.Id)}>
                        <Icon style={{color: "red"}} path={mdiStop} size={1} />
                    </button> 
                </div>}
            </div>
        </>
    )
}

Edit: I’ve added the mapping of the component below to show that there are unique keys (the Id prop) being passed through.

    return (
        <>
            <div className="app-main-container">
                <div className="docker-containers">
                    {containers.map((container: ContainerProps) => {
                        return (
                            <Container Id={container.Id} State={container.State} Status={container.Status}
                                Names={container.Names} Labels={container.Labels}/>
                        )
                    })}
                </div>
            </div>
        </>
    )

2

Answers


  1. It seems you have one State defined and you are using this one state (the same instance,the same time) in all of your expandable buttons.
    As we don’t see your code for the mapping it could be possible that you have not given an ID to each of the expandable button instances.
    Try to map them with a explicit key.

    Here is a link to a resource where you can read about the problem:

    https://medium.com/geekculture/using-reacts-state-to-update-css-dynamically-c9b45570340c

    Login or Signup to reply.
  2. The way i solved this is by making the btn a separate component and pass the state as prop like this:

    <ContainerButton onclick={setExpanded(!expanded)} ...props />
    

    OK i will show how i do it in my project, the one thing i did not tell you is that i pass a function which has the change state inside it maybe thats the trick:

    mapping

    <div className='pt-4'>
      {CarsModalCardData.map((item, index) => (<CarExpandCard key={index} item={item} />))}
    </div>
    

    expand component

    function CarExpandCard({ item }) {
      const [openCarInfo, setOpenCarInfo] = useState(false);
    
      const setExpandState = () => {
        setOpenCarInfo(!openCarInfo)
      };
    
      return (
        <>
          <div className='py-2 space-y-1'>
            <div key={item.id} className='w-full p-4 text-xs rounded-lg bg-quaternary'>
              <div className=''>
                <ExpandButton onclick={setExpandState} title={item.car} secondary={item.owner} />
    
              </div>
              {openCarInfo &&...}
    

    Expand button

    function ExpandButton({ onclick, title, secondary }) {
      
      return (
        <div className='flex items-center justify-between w-full'>
          <div className='flex items-center space-x-1'>
            <div className='flex items-center space-x-2'>
    
              {secondary &&
                <div className='w-2 h-2 rounded-full bg-blue_custom'></div>
              }
              <h3>{title}</h3>
            </div>
            <h3 className='text-textTertiary'>{secondary}</h3>
          </div>
    
          <button onClick={onclick} type='button' className={`${!onclick && "rotate-180"} p-2`}>
            <ExpandIcon />
          </button>
        </div>
      )
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search