How to change the specfic component inside an li tag (reactjs);

Viewed 266

I have written a react functional component that has an unordered list in it. Each li has a specific key for it. Inside the the li there is a div tag and an button in it. I need to change the state of the specific button on click.

    <div>
        <ul>
            {data.map((value,index) => {
                return <li key={value.id}>
                    <div>
                        {value.name}
                    </div>
                    <button
                    onClick={changethislistate}
                    >
                        click
                    </button>
                </li>
            })}
        </ul>
    </div>

On click of the click button I need to change the value from click to clicked for that li only. And also I need to do it in a functional component.

3 Answers

Create a component for the li items, this way every item can manage it's own state:

const ListItem = ({value}) => {
  const [clicked, setClicked] = useState(false);
  return (
    <li>
      <div>{value.name}</div>
      <button onClick={()=> setClicked(prev => !prev)}>{clicked ? "clicked" : "click"}</button>
    </li>
  );
};

then:

<div>
   <ul>
     {data.map((value,index) => {
        return <ListItem key={value.id} value={value} />        
     })}
   </ul>
</div>

Add a state to the component, that is an object and use the index as keys:

const App = (props) => {
  const [state, setState] = React.useState({ 0: false, 1: true });

  const changethislistate = (id) => {
    setState((prev) => ({ ...prev, [id]: !prev[id] }));
  };

  const data = [{ name: "First" }, { name: "Second" }];
  return (
    <div>
      <ul>
        {data.map((value, index) => {
          return (
            <li key={value.id}>
              <div>{value.name}</div>
              <button onClick={() => changethislistate(index)}>
                {state[index] ? "clicked" : "click"}
              </button>
            </li>
          );
        })}
      </ul>
    </div>
  );
};

Here is a working codepen to play with it.

On Additional to answer up, you can change that without using state. You can use ref's.

import React, { useRef } from 'react';

const App = () => {
  const data = [{id:1,name:"test1"},{id:2,name:"test2"}];
  const ref =useRef([]);
  const changethislistate=(id)=>{
    ref.current[id].innerText="clicked"
  }
  
  return (<div>
  <ul>
      {data.map((value,index) => <li key={value.id}>
              <div >
                  {value.name}
              </div>
              <button 
              ref={(element) => ref.current[index] = element}
              onClick={()=>changethislistate(index)}
              >
                  click
              </button>
          </li>
      )}
  </ul>
</div>)
}
export default App;
Related