【问题标题】:Undefined error when clicking on checkbox in ReactJs单击 ReactJs 中的复选框时出现未定义的错误
【发布时间】:2021-07-06 06:28:24
【问题描述】:

我是 ReactJS 的新手,我正在尝试制作一个待办事项列表。后端是 Java Spring Boot。

我只有一个复选框和一个字符串(字符串是列表的任务名称,比如“去购物”)

如果我点击复选框,我会收到错误:

一个组件正在改变一个不受控制的输入以被控制。这可能是由于值从未定义更改为已定义值引起的,这不应该发生。决定在组件的生命周期内使用受控输入元素还是不受控输入元素。

这是我的 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;

这是我的 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;

我有点知道错误是因为复选框未定义。但我不明白为什么复选框未定义,因为它来自 App.js。

这是后端: 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;
    }
}

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

尝试将checked 替换为defaultChecked

默认 prop 是 null 所以但很明显它是未定义的,因为你是从 null 访问 isDone

添加!!之前todoItem.isDone

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

!!将值转换为布尔值,所以 undefined 是假值,所以最终它会是假的

【讨论】:

  • 谢谢,现在我没有收到错误。但是checked和defaultChecked有什么区别呢?看起来,如果我刷新页面,复选框状态不会被保存。其实就算刷新也应该保存?
  • 您正在使用 onChange 控制该输入复选框,因此它应该具有 defaultChecked 表示该属性的默认值
  • 好的,谢谢。你有什么想法,为什么当我刷新页面时复选框的状态没有保存?
  • 那么当您在应用组件中刷新时,您的 API 是否会返回正确的响应?
  • 其实是的。我将后端代码发布到问题中。你能看看吗?
猜你喜欢
  • 2015-07-08
  • 2021-09-11
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
  • 2019-02-24
  • 2014-03-21
相关资源
最近更新 更多