Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

toggle active state with hooks react

I am using React hooks and have come across something that I am unsure how to do.

I have a parent component that renders a list of cities.

const Cities = ({ cities = ["London", "Barcelona", "Los Angeles", "New York"] }) => {
  return (
    <>
      {cities.map(city => {
        const [isActive, setActive] = useState(false);
        return <p onClick={() => setActive(true)} style={{ color: isActive ? "red" : "green" }}>{city}</p>;
      })}
    </>
  );
};

the problem I am having is that every time I click on a city it turns red, however I only want one to be red at any one time (i.e. the most recently clicked one).

If anything is unclear with this question please let me know.

In a class component I guess I would potentially do something similar to this.

See code sandbox here.

like image 335
peter flanagan Avatar asked Jan 26 '23 21:01

peter flanagan


2 Answers

If only one city can be selected at a time, you do not require to have a state value for all of them. Just keep the currently selected one in a single state attribute :

const Cities = ({ cities = ["London", "Barcelona", "Los Angeles", "New York", "Wigan"] }) => {
    const [activeCity, setCity] = useState(null);

    return (
        <>
            {cities.map(city => <p key={city} onClick={() => { setCity(city) }} style={{ color: activeCity === city ? "red" : "green" }}>{city}</p>)}
        </>
    );
};
like image 55
Treycos Avatar answered Jan 29 '23 10:01

Treycos


If only a single city can be red, you shouldn't use the hook inside the loop (something that actually you should never do) but keep a single active state above the rendering, something like:

const App = ({ cities = ["London", "Manchester", "Leeds"] }) => {
  const [active, setActive] = useState(false)

  const City = ({ name }) => (
    <p
      onClick={ () => setActive(name) }
      style={{ color: active === name ? "red" : "green" }}
    >
      { name }
    </p>
  )

  return (
    <>
      { cities.map(city => <City name={ city } />) }
    </>
  );
};

You can find my working codesandbox here: https://codesandbox.io/s/o58342l64z

I also took the freedom to refactor a bit for personal clarity.

like image 25
0xc14m1z Avatar answered Jan 29 '23 10:01

0xc14m1z