2

I am new to ReactJS and I am trying to make a todo list. The backend is Java Spring Boot.

I just have a checkbox and a string (string is the task name for the list, like "go shopping")

If I click on the checkbox I get the error :

A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.

This is my App.js:

import { useEffect, useState } from 'react';
import './App.css';
import TodoItem from './components/todoItem';

function App() {

  const [todoItems, setTodoItems] = useState(null);

  useEffect(() => {
    console.log("Hey loading");

  if (!todoItems){
  fetch('http://localhost:8080/api/todoItems')
  .then((res) => res.json())
  .then((data) => {
    console.log("todo items list: ", data);
    setTodoItems(data);
  });
}
}, [todoItems]); //depends on todoItems
  return (
  <div>
    {todoItems ?  todoItems.map((todoItem) => {
      return (
        <TodoItem 
        key={todoItem.id}
        data = {todoItem} />
      );
    }) 
    : 'loading data..'}
  </div>
  );
}

export default App;

This is my todoItem.jsx

import React, { useEffect, useState } from 'react';

const TodoItem = (props) => {

    const[todoItem, setTodoItem] = useState(props.data);
    //const[getter, setter]
    const [isDirty, setDirty] = useState(false);


    useEffect( () => {
        if(isDirty){
        fetch('http://localhost:8080/api/todoItems/'+todoItem.id, {
            method: 'PUT',
            headers: {
                "content-type": "application/json"
            },
            body: JSON.stringify(todoItem),
        })
        .then(response => response.json())
        .then((data) => {
            setDirty(false);
            setTodoItem(data)
        });
    }
        console.log("hey the todo is changing", todoItem);
        
    }, [todoItem, isDirty]);

    return ( 
    <>
        <input type ="checkbox" checked = {todoItem.isDone}
         onChange={() => {
            setDirty(true);
            setTodoItem({ ...todoItem, isDone: !todoItem.isDone });
        }}
        />
        <span>{todoItem.task}</span>
    </>
    );
};

export default TodoItem;

I kinda know that the error comes because the checkbox is undefined. But I cannot understand why the checkbox is undefined since it comes from App.js.

Here is the backend: ToDoController.java

@RestController
@CrossOrigin(origins = "http://localhost:3000")
public class ToDoController {

    @Autowired
    private TodoService todoService;

    @RequestMapping(value = "/api/todoItems", method = RequestMethod.GET)
    public ResponseEntity<?> fetchAllToDoItems(){
       List<TodoItem> todoItemList =  todoService.fetchAllTodoItems();
       return ResponseEntity.status(HttpStatus.OK).body(todoItemList);

    }

    @RequestMapping(value="/api/todoItems/{id}", method = RequestMethod.PUT)
    public ResponseEntity<?> updateTodoItem(@PathVariable Integer id, @RequestBody TodoItem todoItem){
        TodoItem updateTodoItem =todoService.updateTodoItem(id, todoItem);
        return ResponseEntity.ok(updateTodoItem);

    }
}

ToDoService.java

    @Service
public class TodoService {


    @Autowired
    private TodoRepository todoRepository;

    public List<TodoItem> fetchAllTodoItems (){
        return todoRepository.fetchAllTodoItems();
    }

    public TodoItem updateTodoItem(Integer id, TodoItem todoItem){
        Optional<TodoItem> todoItemOptional = todoRepository.fetchAllTodoItems()
                .stream()
                .filter(item -> todoItem.getId().equals(id) )
                .findAny();

        if (todoItemOptional.isPresent()) {
            TodoItem item = todoItemOptional.get();
            item.setDone(todoItem.getDone());
            item.setTask(todoItem.getTask());
            return item;
        }
        return null;
    }
}

ToDoRepository.java

@Repository
public class TodoRepository {
    private Integer idCounter =0;

    private List<TodoItem> todoItems = new ArrayList<>();

    public List<TodoItem> fetchAllTodoItems() {
        if (todoItems.size() == 0 ) {
            TodoItem item1 = new TodoItem();
            item1.setId(idCounter++);
            item1.setDone(false);
            item1.setTask("Task #1");

            todoItems.add(item1);
        }
        return todoItems;

    }

}

ToDoItem.java

public class TodoItem {


    private Integer id;
    private String task;
    private Boolean isDone;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTask() {
        return task;
    }

    public void setTask(String task) {
        this.task = task;
    }

    public Boolean getDone() {
        return isDone;
    }

    public void setDone(Boolean done) {
        isDone = done;
    }
}
1

1 Answer 1

2

Try replacing checked with defaultChecked

and default prop is coming as null so but obvious it would undefined because you are access isDone from null

Add !! before todoItem.isDone

<input type ="checkbox" defaultChecked= {!!todoItem.isDone}
         onChange={() => {
            setDirty(true);
            setTodoItem({ ...todoItem, isDone: !todoItem.isDone });
        }}
        />

!! converts value to Boolean value so undefined is false value so ultimately it will be false

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

7 Comments

Thanks, now I don't get the error. But what is the difference between checked and defaultChecked? And it looks like, if I refresh the page, the checkbox state is not saved. Actually it should be saved, even if I refresh?
You are controlling that input checkbox using onChange so it should have defaultChecked which says default value for that attribute
ok makes sense, thanks. And do you have an idea, why the state of the checkbox is not saved, when I refresh the page?
so does your API return the proper response when you refresh, in the app component?
actually yes. I posted the backend code to the question. can you pls have a look?
|

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.