0

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);

2 Answers 2

1

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>

Sign up to request clarification or add additional context in comments.

Comments

0

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} />;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.