当前的建议是不再使用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;
那么现在推荐的处理这种情况的方法是什么?
答案 0 :(得分:0)
在我看来,受控组件意味着它是由其他组件控制的。因此,我们将道具发送到子组件,并在子组件中使用它们。您无需为此组件设置单独的状态。您始终可以在render方法中使用props(除非您需要根据props进行一些计算,而这些props仍可以在不使用状态的情况下进行处理。)
如果我们使用道具,我们可以跳过编写componentwillreceiveprops方法。 如果要处理表单,为什么不使用状态提升并调用父组件方法? 这样,您当前的组件将得到控制,并且可以在应用程序的任何其他位置重用。 (因为,我们将使用父组件提供的任何东西,而子组件仅消耗道具并在需要时调用父方法)
答案 1 :(得分:0)
同时建议使用受控组件 而不是使用表格时不受控制的组件
这部分正确。您可以使用:
此外,您添加的代码是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);