William
William

Reputation: 61

How to handle click event to change value in array to true

I want to make a handleItemClick event to toggle the value in done to true, how can I do it? I am struggling to understand how to change it. Thanks a lot for your help I realll appreciate it

const TodoItem = (props) => <li onClick={props.onClick}>{props.item.text}</li>

class TodoList extends React.Component {
  render() {
    const { items, onClick } = this.props;
    return (<ul onClick={onClick}>
      {items.map((item, index) => 
                 <TodoItem item={item} key={index} onClick={this.handleItemClick.bind(this, item)}/>)}
    </ul>);
  }

  handleItemClick(item, event) {
    // Write your code here
  }
}


const items = [ { text: 'Buy grocery', done: true },
  { text: 'Play guitar', done: false },
  { text: 'Romantic dinner', done: false }
];

const App = (props) => <TodoList
  items={props.items}
  onItemClick={(item, event) => { console.log(item, event) }}
/>;

document.body.innerHTML = "<div id='root'></div>";
const rootElement = document.getElementById("root");
ReactDOM.render(<App items={items}/>, rootElement);

Upvotes: 0

Views: 1023

Answers (2)

HMR
HMR

Reputation: 39270

You can have App own the list of todo items and pass the items and setItems function you got from setState.

Using setState and passing it has a disadvantage because you can't easily use useCallback to optimize the handlers but the following will work:

const TodoItem = props => (
  <li onClick={props.onClick}>
    {props.item.text} {String(props.item.done)}
  </li>
);

const TodoList = ({ items, setItems }) => {
  const onClick = id => () =>
    setItems(
      items.map(item =>
        item.id === id
          ? { ...item, done: !item.done }
          : item
      )
    );
  return (
    <ul>
      {items.map(item => (
        <TodoItem
          item={item}
          //never use index for list especially if you remove
          // or re arrange them
          key={item.id}
          onClick={onClick(item.id)}
        />
      ))}
    </ul>
  );
};

const App = props => {
  //someone needs to own items so when you change it
  // it will cause a re render
  const [items, setItems] = useState([
    { id: 1, text: 'Buy grocery', done: true },
    { id: 2, text: 'Play guitar', done: false },
    { id: 3, text: 'Romantic dinner', done: false },
  ]);
  return <TodoList items={items} setItems={setItems} />;
};

Upvotes: 0

skovy
skovy

Reputation: 5650

With your current setup, the items are passed in as props. At some point, these items need to become component state so that they can be updated.

One option is to accept the items as props and use them as the initial state in the TodoList. However, what you like want is for the App component to have these set as the initial state in the useState hook.

Then pass the onItemClick prop so that a click on the TodoItem component can call this method and update the proper item.

const TodoItem = props => (
  <li onClick={props.onClick}>
    {props.item.text} - {props.item.done.toString()}
  </li>
);

class TodoList extends React.Component {
  render() {
    const { items, onItemClick } = this.props;

    return (
      <ul>
        {items.map((item, index) => (
          <TodoItem item={item} key={index} onClick={() => onItemClick(item)} />
        ))}
      </ul>
    );
  }
}

const App = () => {
  const [items, setItems] = React.useState([
    { text: "Buy grocery", done: true },
    { text: "Play guitar", done: false },
    { text: "Romantic dinner", done: false }
  ]);

  return (
    <TodoList
      items={items}
      onItemClick={itemToUpdate => {
        const updatedItems = items.map(item => {
          if (item === itemToUpdate) {
            return { ...item, done: !item.done };
          } else {
            return item;
          }
        });
        setItems(updatedItems);
      }}
    />
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions