【问题标题】:Update state through React functional component checkbox通过 React 功能组件复选框更新状态
【发布时间】:2020-07-16 15:52:20
【问题描述】:

每次选中/取消选中复选框时,我都会尝试更新渲染的卡片。目前,我在试图弄清楚如何更新 todos 状态时遇到了麻烦,该状态是一个包含多个 JSON 的数组:

[{"_id":"fhrgiu34hnt","todo_description":"Lunch","todo_responsible":"1:30PM","todo_priority":"High","todo_completed":true,"todo_id":"fhrgiu34hnt"},{"_id":"fgvjhbansfgki35sn","todo_description":"Dinner","todo_responsible":"7:45PM","todo_priority":"High","todo_completed":true,"todo_id":"fgvjhbansfgki35sn"},{"_id":"sfgvhio3t58","todo_description":"Supper","todo_responsible":"10:30PM","todo_priority":"Medium","todo_completed":false}]

当通过 onChange 调用 changedBox 时值得到更新,但由于(错误地)尝试比较 componentDidUpdate 中的待办事项而没有重新渲染?当我手动刷新页面时,复选框的更新值将再次呈现。有没有办法可以更新组件 Todo 中已检查的待办事项,以便正确呈现?

这是我目前拥有的:

import React, {Component} from 'react';
import {useState, useEffect} from 'react';
import {Link} from 'react-router-dom';
import axios from 'axios';

const changedBox = (e, props) => {

    const completed = e;
    console.log("Inside changedBox");
    console.log("Trying to update - ID: " + props.todo._id);
    console.log("Checkbox is currently: " + completed);
    const obj = {
        todo_id: props.todo._id,
        todo_description: props.todo.todo_description,
        todo_responsible: props.todo.todo_responsible,
        todo_priority: props.todo.todo_priority,
        todo_completed: completed
    };
    axios.post('example.com/api', obj)
        .then(response => console.log(response.data));
};

function Todo (props) {
    let [t] = useState(props.todo);
    console.log(t)
    console.log(JSON.stringify(t));
    useEffect(() => {
        console.log("Inside useEffect");
        axios.get('example.com/api')
            .then(response => {
                t = props.todo;
            })
            .catch(function (error) {
                console.log(error);
            })

    })

    return (
        <div className="card" key={props.todo._id}>
            <div className="card-body">

                <input type="checkbox" id={props.todo._id} checked={props.todo.todo_completed}
                       onChange={event => changedBox(!props.todo.todo_completed, props)}/>
                <label htmlFor={props.todo._id}/>

                <div className="card-title">
                    <h4> {props.todo.todo_description} </h4>
                    <h6> {props.todo.todo_responsible} </h6>
                    <h6> {props.todo._id ? props.todo._id : "No ID yet"} </h6> {/* Debugging */}
                    <h6> {props.todo.todo_priority} </h6> {/* Debugging */}
                    <span
                        className="badge badge-info"> {props.todo.todo_completed ? "Completed" : "Not Completed"} </span>
                </div>

                <div className="dropdown card-options">
                    <Link to={"/edit/" + props.todo._id}
                          style={{color: 'inherit', textDecoration: 'inherit'}}>
                        <button className="btn-options" type="button">
                            <i className="fas fa-ellipsis-v"/>
                        </button>
                    </Link>
                </div>

            </div>

        </div>

    )
}

class TodosList extends Component {
    _isMounted = false;

    constructor(props) {
        super(props);
        this.state = {
            todos: []
        };
    }

    componentDidMount() {
        this._isMounted = true;
        axios.get('example.com/api')
            .then(response => {
                if (this._isMounted) {
                    this.setState({todos: response.data});
                }
            })
            .catch(function (error) {
                console.log(error);
            })
    }

    componentDidUpdate(prevProps, prevState, ss) {

        console.log("prevState.todos: " + prevState.todos);
        console.log(JSON.stringify(prevState.todos));

        console.log("Comparing JSON.stringify(this.state.todos) !== JSON.stringify(prevState.todos): " + (JSON.stringify(this.state.todos) !== JSON.stringify(prevState.todos)));

        if (JSON.stringify(this.state.todos) !== JSON.stringify(prevState.todos)) {

            console.log("Inside componentDidUpdate - Attempting to update!");
            axios.get('example.com/api')
                .then(response => {
                    this.setState({todos: response.data});
                })
                .catch(function (error) {
                    console.log(error);
                });
        }
    }

    componentWillUnmount() {
        this._isMounted = false;
    }


    todoList() {
        return this.state.todos.map(function (currentTodo, i) {
            console.log("Todo ID: " + currentTodo._id + ", Num: " + i);
            return <Todo todo={currentTodo} key={i} ind={i}/>;
        });
    }

    render() {

        return (
            <div className="card-container">
                <h3>List</h3>
                {this.todoList()}
            </div>
        )
    }
}

export default TodosList;

【问题讨论】:

    标签: reactjs react-hooks react-props react-component


    【解决方案1】:

    您可以在这里做得更好。

    首先,useState 返回 2 个元素的数组,第一个是数据,第二个 - 更新函数, 因此,每当您使用 useState 并且想要更新状态时,请这样做:

    const [data, setData] = useState('some data');
    
    setData('I want to update it');
    

    然后组件会重新渲染。

    这应该是固定的

    .then(response => {
      // t = props.todo;
      setTodo(props.todo);
    })
    

    changedBox 方法不会导致组件重新渲染,因为它没有改变状态,请再次使用setTodo

        const obj = {
            todo_id: props.todo._id,
            todo_description: props.todo.todo_description,
            todo_responsible: props.todo.todo_responsible,
            todo_priority: props.todo.todo_priority,
            todo_completed: completed
        };
    

    setTodo(obj)

    我看到你混合使用了钩子和基于类的组件,尝试使用其中之一,它会让你的代码更加一致。

    【讨论】:

    • 我已经设法通过转换为类组件并使用 setState 解决了这个问题。感谢您的建议!
    猜你喜欢
    • 2020-08-12
    • 2021-01-12
    • 2021-10-07
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2013-05-08
    • 2021-01-06
    • 2021-02-15
    相关资源
    最近更新 更多