Farhan Bin Amin
Farhan Bin Amin

Reputation: 60

Checking the checkbox is not working in React

This is a simple TO-DO app in react in which App.js takes data from TodosData.js and the list is shown with the component TodoItem.js. Now the checkboxes and data can be viewed when rendered. But when I click on the checkbox it doesn't work. I tried console logging handleChange function which seems to work. It seems like there maybe problems inside the handleChange function which I can't figure out.

I am following a freecodecamp tutorial on YT and I also checked it several times but can't find the problem here.

App.js code:

import React from 'react';
import TodoItem from './TodoItem'
import todosData from './todosData'

class App extends React.Component {
  constructor() {
    super ()
    this.state = { todos: todosData }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(id) {
    this.setState(prevState => {
      const updatedTodos = prevState.todos.map(todo => {
        if (todo.id === id) {
          todo.completed = !todo.completed
        }
        return todo
      })
      return {
        todos: updatedTodos
      }
    })
  }

  render() {
    const todoItems = this.state.todos.map(itemEach => <TodoItem key = {itemEach.id} itemEach = {itemEach}
      handleChange = {this.handleChange} />)
    return (
      <div className = "todo-list">
        {todoItems}
      </div>
    )
  }
}

export default App;

TodoItem.js code:

import React from 'react';

function TodoItem(props) {
  return(
    <div className = "todo-item">
      <input type = "checkbox"
        checked={props.itemEach.completed}
        onChange={() => props.handleChange(props.itemEach.id)}
      />
      <p>{props.itemEach.text}</p>
    </div>
  )
}

export default TodoItem

TodosData.js code:

const todosData = [
  {
    id: 1,
    text: "Take out the trash",
    completed: true
  },
  {
    id: 2,
    text: "Grocery shopping",
    completed: false
  },
  {
    id: 3,
    text: "Clearn gecko tank",
    completed: false
  },
  {
    id: 4,
    text: "Mow lawn",
    completed: true
  },
  {
    id: 5,
    text: "Catch up on Arrested Development",
    completed: false
  }
]

export default todosData

Is there a better way to implement this? This way of doing checkbox seems quite complicated for a beginner like myself. Also how can I improve this code?

Upvotes: 0

Views: 99

Answers (1)

tanmay
tanmay

Reputation: 7911

You are mutating the state in your handleChange function. Hence it gets the prevState twice. Once for the original previous state, next for the update that you make inside the handleChange.

You can probably lose the reference, by spreading the todo from state like this.

this.setState(prevState => {
  const updatedTodos = prevState.todos.map(todo => {
    const resTodo = { ...todo };
    if (todo.id === id) {
      resTodo.completed = !resTodo.completed;
    }
    return resTodo;
  });
  return {
    todos: updatedTodos
  };
});

Here's a working codesandbox

Upvotes: 1

Related Questions