0

I have a component (which renders a list element). When clicked a state isActive in that component will be set to true. But I want the other components isActive state to be set to false. But I can't seem to figure out how to set the state of a different component when interacting with an component.

https://codesandbox.io/s/eloquent-elbakyan-5powe?file=/src/App.tsx

export const ListElement = () => {
  const [isActive, setIsActive] = React.useState(false)
  const handleClick = () => {
    setIsActive(!isActive)
  }
  return (
    <li
      onClick={handleClick}
      className={isActive ? 'active' : ''}
    >
      toggle between these elements
    </li>
  )
}
Peter Boomsma
  • 8,851
  • 16
  • 93
  • 185
  • Communicate the state to a common parent/ancestor that in turn sets the states of the related children/descendant. This is outlined in many tutorials and even react documentation itself https://react-cn.github.io/react/tips/communicate-between-components.html – Ruan Mendes Nov 06 '21 at 15:06
  • 2
    Does this answer your question? [ReactJS Two components communicating](https://stackoverflow.com/questions/21285923/reactjs-two-components-communicating) and https://reactjs.org/docs/lifting-state-up.html – Ruan Mendes Nov 06 '21 at 15:06
  • I thought about that, but if I pass a prop to an parent element (the UL component for example) and set all the child components (the list elements) to false. It would also set the clicked element to false. – Peter Boomsma Nov 06 '21 at 15:07
  • Not sure what you mean, each child element has an ID, when you get an event saying a child item became active, you set all the other child items to inactive. Your list item needs to have an input prop to set it to inactive and a callback to let its parent know it has changed. The dirty way is to set them all to inactive and then set the one that sent the event top active. – Ruan Mendes Nov 06 '21 at 15:09

1 Answers1

0

A workaround is to have the active state in parent component, and then passing some functions and data to child, to handle what you want

Sandbox

//Parent

import { useState } from "react";

export default function App() {
  const [activeId, setActiveId] = useState();
  const [lists] = useState([0, 1, 2, 3]);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>

      <ul>
        {lists.map((list, id) => (
          <ListElement
            id={id}
            key={id}
            isActive={id === activeId}
            toggle={setActiveId}
          />
        ))}
      </ul>
    </div>
  );
}


//ListElement

export const ListElement = ({toggle,isActive,id}) => {
  return (
    <li
      onClick={()=>toggle(id)}
      className={isActive ? 'active' : ''}
    >
      toggle between these elements
    </li>
  )
}
Tiko
  • 1,241
  • 11
  • 19
  • Oh yea, you can pass the the ListElement id as a identifier between all the list elements. Smart. Thanks – Peter Boomsma Nov 06 '21 at 15:15
  • @PeterBoomsma DIdn't I already say that each item should have an ID you can pass around in my comment? Tiko: We really don't need another answer on StackOverflow answering the same question for the millionth time... As much as we want to help posters, there are plenty of answers explaining this in detail – Ruan Mendes Nov 06 '21 at 15:20