Как исправить ошибку «Предупреждение: компонент изменяет контролируемый вход на неконтролируемый»

#reactjs

Вопрос:

Я получаю эту ошибку ниже. Где в моем коде проблема? Решения, которые я видел в google или stackoverflow, до сих пор не помогли.

Предупреждение: Компонент изменяет контролируемый вход на неконтролируемый. Вероятно, это вызвано изменением значения с определенного на неопределенное, чего не должно произойти. Решите, использовать ли управляемый или неконтролируемый входной элемент в течение всего срока службы компонента.

Есть 2 файла, в которых содержится большая часть кода моего клиента. ContactForm.js amp; Contact.js

Учебник, в котором я застрял, заключается в следующем. В 37:27 мы видим, как щелкнул значок редактирования, и он заполняет поля, и это происходит не со мной.

Исходный код находится здесь.

ContactForm.js

 import React, { useState, useEffect } from "react";
const ContactForm = (props) => {
    const initialFieldValues = {
        fullName: "",
        mobile: "",
        email: "",
        address: ""
    }
    var [values, setValues] = useState(initialFieldValues)

    useEffect(() => {
        if (props.currentId == "")
            setValues({ ...initialFieldValues })
        else
            setValues({
                ...props.contactObjects[props.currentId]
            })
    }, [props.currentId, props.contactObjects])

    const handleInputChange = e => {
        var { name, value } = e.target;
        setValues({
            ...values,
            [name]: value
        })
    }
    const handleFormSubmit = e => {
        e.preventDefault();
        props.addOrEdit(values)
    }
    return (
        <form autoComplete="off" onSubmit={handleFormSubmit}>

            <div className="form-row">
                <div className="form-group input-group">
                    <div className="input-group-prepend">
                        <div className="input-group-text">
                            <i className="fas fa-user"></i>
                        </div>
                    </div>
                    <input className="form-control" name="fullName" placeholder="Full Name"
                        value={values.fullName}
                        onChange={handleInputChange}
                    />
                </div>
                <div className="form-group input-group col-md-6">
                    <div className="input-group-prepend">
                        <div className="input-group-text">
                            <i className="fas fa-mobile-alt"></i>
                        </div>
                    </div>
                    <input className="form-control" name="mobile" placeholder="Mobile"
                        value={values.mobile}
                        onChange={handleInputChange}
                    />
                </div>
                <div className="form-group input-group col-md-6">
                    <div className="input-group-prepend">
                        <div className="input-group-text">
                            <i className="fas fa-envelope"></i>
                        </div>
                    </div>
                    <input className="form-control" name="email" placeholder="Email"
                        value={values.email}
                        onChange={handleInputChange}
                    />
                </div>


            </div>
            <div className="form-group">
                <textarea className="form-control" name="address" placeholder="Address"
                    value={values.address}
                    onChange={handleInputChange}
                />
            </div>
            <div className="form-group">
                <input type="submit" value="Save" className="btn btn-primary btn-block" />
            </div>
        </form>
    );
}

export default ContactForm;
 

Contacts.js

 import React, { useState, useEffect } from "react";
import ContactForm from "./ContactForm"
import firebaseDb from "../firebase";

const Contacts = () => {

    var [contactObjects, setContactObjects] = useState({})
    var [currentId, setCurrentId] = useState("")

    //Once components load complete
    useEffect(() => {
        firebaseDb.child("contacts").on("value", snapshot => {
            if (snapshot.val() != null) {
                setContactObjects({
                    ...snapshot.val()
                });
            }
        })
    }, []) // Similar to componentDidMount

    const addOrEdit = (obj) => {

        firebaseDb.child('contacts').push(
            obj,
            err => {
                if (err)
                    console.log(err)
            })

    }
    return (
        <>
            <div class="jumbotron jumbotron-fluid">
                <div class="container">
                    <h1 class="display-4 text-center">Contact Register</h1>
                </div>
            </div>
            <div className="row">
                <div className="col-md-5">
                    <ContactForm {...({ currentId, contactObjects, addOrEdit })} ></ContactForm>
                </div>

                <div className="col-md-7">
                    <div>
                        <table className="table table-borderless table-stripped">
                            <thead className="thead-light">
                                <tr>
                                    <th>Full Name</th>
                                    <th>Mobile</th>
                                    <th>Email</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                {
                                    Object.keys(contactObjects).map(id => {
                                        return <tr key={id}>
                                            <td>{contactObjects[id].fullName}</td>
                                            <td>{contactObjects[id].mobile}</td>
                                            <td>{contactObjects[id].email}</td>

                                            <td className="bg-light">
                                                <a className="btn text-primary" onClick={() => { setCurrentId() }}>
                                                    <i className="fas fa-pencil-alt"></i>
                                                </a>
                                                <a className="btn text-danger" >
                                                    <i className="far fa-trash-alt"></i>
                                                </a>
                                            </td>
                                        </tr>
                                    })
                                }
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </>

    );
}

export default Contacts;
 

Ответ №1:

Ад. Я думаю, что проблемы возникают при вызове setCurrentId функции в Contacts.js файле.

Параметр не задан, что означает, что currentId интерпретируется как undefined .

Вы можете обновить контактную форму, как показано ниже.

 ...
useEffect(() => {
    if (!props.currentId)
        setValues({ ...initialFieldValues })
...
 

Комментарии:

1. Спасибо. Я добавил ссылку на свой исходный код. Ваше предложение устранило ошибку, но при нажатии на кнопку редактирования поля по-прежнему заполняются, как и ожидалось, здесь в 37:24 youtu.be/pI4438IHBYY?t=2244 Ты видишь, в чем дело?

2. Вы вызываете setCurrentId без параметра, что означает, что он все время не определен. Заменить {setCurrentId()} на { secCurrentId(id) } в Contacts.js функция.