受控组件和道具,不带componentWillReceiveProps()

时间:2019-04-04 02:56:50

标签: reactjs

当前的建议是不再使用componentWillReceiveProps()方法。同时,建议在使用表单时使用受控组件而不是非受控组件。

但是,在我看来,从道具接收初始形式值时,这两个概念似乎是矛盾的。

以前,我是按照以下方式创建我的课程的:

class UserDetails extends React.Component {
    constructor(props){
        super(props)

        this.state = {
            first_name: this.props.user.first_name,
            last_name: this.props.user.last_name
        }
    }

   componentWillReceiveProps(nextProps){
          //update state with new props
   }


    async handleSave(){
         //send data to the api from the state
    }

    handleChange(event){
         //sets state based on changes to form field
    }

    render(){
          return (
              <div>
                   <Input id="first_name" value={this.state.first_name} handleChange={(evt)=>{this.handleChange(evt)}} />
                   <Input id="last_name" value={this.state.last_name} handleChange={(evt)=>{this.handleChange(evt)}} />
                   <button onClick={()=>this.handleSave()}>Save Changes</button>
              </div>
          )

    }

}

导出默认UserDetails;

那么现在推荐的处理这种情况的方法是什么?

3 个答案:

答案 0 :(得分:0)

在我看来,受控组件意味着它是由其他组件控制的。因此,我们将道具发送到子组件,并在子组件中使用它们。您无需为此组件设置单独的状态。您始终可以在render方法中使用props(除非您需要根据props进行一些计算,而这些props仍可以在不使用状态的情况下进行处理。)

如果我们使用道具,我们可以跳过编写componentwillreceiveprops方法。 如果要处理表单,为什么不使用状态提升并调用父组件方法? 这样,您当前的组件将得到控制,并且可以在应用程序的任何其他位置重用。 (因为,我们将使用父组件提供的任何东西,而子组件仅消耗道具并在需要时调用父方法)

答案 1 :(得分:0)

  

同时建议使用受控组件   而不是使用表格时不受控制的组件

这部分正确。您可以使用:

  1. 受控组件。
  2. 带有钥匙的完全不受控制的组件。

此外,您添加的代码是anti-pattern,因为您要基于state擦除props。您还有一个handleChange,它将根据用户的输入值setState。因此,这里的问题是,有两个真相来源,而不是一个用于设置state的地方。

根据您的用例,您想要一个props的初始值,然后可以使用一个完全不受控制的组件以及一个密钥来实现此目的。

这意味着我们的组件仍可以接受prop作为初始值,但是它将忽略对该prop的后续更改。

您可以了解有关此模式和反模式here

答案 2 :(得分:0)

我要使用的方法是使用componentDidUpdate并检查属性user是否已更改。

这是带有代码的Hooks附加奖励重构;)

使用componentDidUpdate

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

/// WITHOUT HOOKS

class UserDetails extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      first_name: this.props.user.first_name,
      last_name: this.props.user.last_name
    };
  }

  componentDidUpdate(prevProps) {
    if (this.props.user !== prevProps.user) {
      this.setState({
        ...this.props.user
      });
    }
  }

  async handleSave() {
    //send data to the api from the state
    console.log(this.state);
  }

  handleChange = field => e => {
    this.setState({
      [field]: e.target.value
    });
  };

  render() {
    console.log("rendering");
    return (
      <div>
        <label>{`User: ${this.state.first_name}`}</label>
        <br />
        <input
          id="first_name"
          value={this.state.first_name}
          onChange={this.handleChange("first_name")}
        />
        <input
          id="last_name"
          value={this.state.last_name}
          onChange={this.handleChange("last_name")}
        />
        <button onClick={() => this.handleSave()}>Save Changes</button>
      </div>
    );
  }
}

class App extends React.Component {
  state = {
    c: 0,
    user: {
      first_name: "asd",
      last_name: "das"
    }
  };
  handleChangeUser = () => {
    const { c } = this.state;
    this.setState({
      c: 1 + c,
      user: {
        first_name: `asd_${c}`,
        last_name: `asd_${c}`
      }
    });
  };

  render() {
    return (
      <div className="App">
        <UserDetails user={this.state.user} />
        <button onClick={this.handleChangeUser}>change user</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

使用useEffect钩子

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
// WITH HOOKS

function UserDetailsWithHooks(props) {
  const [user, setUser] = useState({
    ...props.user
  });

  const handleChange = field => e => {
    setUser({ ...user, [field]: e.target.value });
  };

  const handleSave = () => {
    console.log(user);
  };

  useEffect(
    () => {
      setUser(props.user);
    },
    [props.user]
  );

  console.log("rendering");
  return (
    <div>
      <label>{`User: ${user.first_name}`}</label>
      <br />
      <input
        id="first_name"
        value={user.first_name}
        onChange={handleChange("first_name")}
      />
      <input
        id="last_name"
        value={user.last_name}
        onChange={handleChange("last_name")}
      />
      <button onClick={() => handleSave()}>Save Changes</button>
    </div>
  );
}

const AppHooks = () => {
  const [c, setC] = useState(0);
  const [user, setUser] = useState({
    first_name: "asd",
    last_name: "das"
  });

  const handleChangeUser = () => {
    const newC = 1 + c;
    setC(newC);
    setUser({
      first_name: `asd_${newC}`,
      last_name: `asd_${newC}`
    });
  };
  return (
    <div className="App">
      <UserDetailsWithHooks user={user} />
      <button onClick={handleChangeUser}>change user</button>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<AppHooks />, rootElement);