React 输入警告:组件正在将文本类型的受控输入更改为不受控制

React Input Warning: A component is changing a controlled input of type text to be uncontrolled

我正在使用一个 Fake API site. For front-end, I am using React typescript and React router dom for routing. I successfully login the email and password by using Fake API's login and redirect to list users, where I fetched the data from Fake API and shows the user's name, image. I used the edit button, after clicking the button it will redirect to my Update components where it will populate the input field then I will update the data. My update components work fine as expected but in my console, I am getting a warning as soon as I type my input field.Here is the Error visualization

练习 REST API

这是 React 更新组件

import React, { useState, useEffect } from "react";
import axios from "axios";

const Update = props => {
  const [state, setState] = useState({
    first_name: "",
    last_name: "",
    email: ""
  });

  const [loading, setLoading] = useState(false);
  useEffect(() => {
    axios
      .get("https://reqres.in/api/users/" + props.match.params.id)
      .then(response => {
        setState({
          first_name: response.data.data.first_name,
          last_name: response.data.data.last_name,
          email: response.data.data.email
        });
      })
      .catch(function(error) {
        console.log(error);
      });
  }, [props.match.params.id]);

  const onChangeFirstName = e => {
    setState({
      first_name: e.target.value
    });
  };

  const onChangeLastName = e => {
    setState({
      last_name: e.target.value
    });
  };
  const onChangeEmail = e => {
    setState({
      email: e.target.value
    });
  };

  const onSubmit = e => {
    e.preventDefault();
    setLoading(true);
    const obj = {
      first_name: state.first_name,
      last_name: state.last_name,
      email: state.email
    };
    axios
      .patch("https://reqres.in/api/users/" + props.match.params.id, obj)
      .then(res => console.log(res.data));
    setLoading(false);
    props.history.push("/users");
  };

  return (
    <div>
      <form onSubmit={onSubmit}>
        <div className="form-group">
          <label>First Name: </label>
          <input
            type="text"
            className="form-control"
            value={state.first_name}
            onChange={onChangeFirstName}
            id="first_name"
          />
        </div>

        <div className="form-group">
          <label>Last Name: </label>
          <input
            type="text"
            className="form-control"
            value={state.last_name}
            onChange={onChangeLastName}
            id="last_name"
          />
        </div>

        <div className="form-group">
          <label>Email: </label>
          <input
            type="email"
            className="form-control"
            value={state.email}
            onChange={onChangeEmail}
            id="email"
          />
        </div>
        <div className="form-group">
          <button
            className="btn waves-effect blue lighten-1"
            type="submit"
            name="action"
            disabled={loading}
          >
            {loading ? "loading..." : "save"}
          </button>
        </div>
      </form>
    </div>
  );
};

export default Update;

有了钩子,当你set the state一个对象时,你需要自己合并所有的属性。换句话说,如果您使用 state updater 更新对象的 属性,则对象的其余属性不会自行合并,这与 class 组件中的 this.setState 不同。

将您的 onChange 修改为这样:

const onChangeFirstName = e => {
    const val = e.target.value;
    setState(prevState => ({
      ...prevState,
      first_name: val
    }));
  };

working demo

还有快速建议: 您可以简化并只使用一个,而不是编写多个 onChange

像这样:

<input
 type="text"
 className="form-control"
 value={state.first_name}
 onChange={onChange}
 id="first_name"
 name="first_name" />

...

const onChange = e => {
    const {name, value} = e.target;
    setState(prevState => ({
      ...prevState,
      [name]: value
    }));
  };