Javascript 使用 React 子组件上的道具更新状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39154967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating state with props on React child component
提问by Adam White
I have a React app, where props from a parent component are passed to a child component and the props then set the state on the child.
我有一个 React 应用程序,其中来自父组件的道具传递给子组件,然后道具在子组件上设置状态。
After I send an updated value to the parent component, the child component isn't updating the state with the updated props.
在我向父组件发送更新的值后,子组件不会使用更新的 props 更新状态。
How do I get it to update the state on the child component?
如何让它更新子组件上的状态?
My pared-down code:
我的精简代码:
class Parent extends React.Component {
constructor (props) {
super(props);
this.state = {name: ''}
}
componentDidMount () {
this.setState({name: this.props.data.name});
}
handleUpdate (updatedName) {
this.setState({name: updatedName});
}
render () {
return <Child name={this.state.name} onUpdate={this.handleUpdate.bind(this)} />
}
}
class Child extends React.Component {
constructor (props) {
super(props);
this.state = {name: ''}
}
componentDidMount () {
this.setState({name: this.props.name});
}
handleChange (e) {
this.setState({[e.target.name]: e.target.value});
}
handleUpdate () {
// ajax call that updates database with updated name and then on success calls onUpdate(updatedName)
}
render () {
console.log(this.props.name); // after update, this logs the updated name
console.log(this.state.name); // after update, this logs the initial name until I refresh the brower
return <div>
{this.state.name}
<input type="text" name="name" value={this.state.name} onChange={this.handleChange} />
<input type="button" value="Update Name" onClick={this.handleUpdate.bind(this)} />
</div>
}
}
回答by Blorgbeard is out
You need to implement componentWillReceiveProps
in your child:
您需要componentWillReceiveProps
在您的孩子中实施:
componentWillReceiveProps(newProps) {
this.setState({name: newProps.name});
}
Edit:componentWillReceiveProps
is now deprecated and will be removed, but there are alternative suggestions in the the docs link above.
编辑:componentWillReceiveProps
现在已弃用并将被删除,但在上面的文档链接中有其他建议。
回答by goldbullet
Calling setState()
in componentWillReceivePropsdoesn't cause additional re-render. Receiving props is one render and this.setState would be another render if that were executed within a method like componentDidUpdate. I would recommend doing the this.state.name !== nextProps.name
in shouldComponentUpdateso it's always checked for any update.
调用setState()
在componentWillReceiveProps不会造成额外的重新渲染。接收 props 是一个渲染,如果在componentDidUpdate之类的方法中执行 this.setState 将是另一个渲染。我建议this.state.name !== nextProps.name
在shouldComponentUpdate 中执行,以便始终检查是否有任何更新。
componentWillReceiveProps(nextProps) {
this.setState({name: nextProps.name});
}
shouldComponentUpdate(nextProps) {
return this.state.name !== nextProps.name;
}
回答by tylermadison
It would also be good to check if you even need to update the state, since this will cause a re-render.
检查您是否甚至需要更新状态也很好,因为这会导致重新渲染。
componentWillReceiveProps(newProps) {
if (this.state.name !== newProps.name) {
this.setState({name: newProps.name});
}
}
回答by Menelaos Kotsollaris
A couple of things. The way you bind the functions on click is unusual to say the least. I would suggest that you either do it on constructor, or use an arrow function instead (this will bind the function to the class automatically).
几件事。您在单击时绑定函数的方式至少可以说是不寻常的。我建议您要么在构造函数上执行此操作,要么改用箭头函数(这将自动将函数绑定到类)。
export default class Parent extends Component {
constructor (props) {
super(props);
this.state = {name: ''}
}
handleUpdate = (updatedName) => {
this.setState({name: updatedName})
}
render () {
return <Child name={this.state.name} onUpdate={this} />
}
}
export default class Child extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
}
componentDidMount() {
this.setState({ name: this.props.name });
}
handleChange = (e) => {
this.setState({ name: e.target.value });
}
handleUpdate() {
// ajax call that updates database with updated name and then on success calls onUpdate(updatedName)
}
render() {
console.log(this.props.name); // after update, this logs the updated name
console.log(this.state.name); // after update, this logs the initial name until I refresh the brower
return (
<div>
{this.state.name}
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleChange}
/>
<input
type="button"
value="Update Name"
onClick={this.handleUpdate}
/>
</div>
);
}
}
Furthermore, I would suggest you to decide whether the props need to be managed/updated from Parent or Child. Should Parent be responsible for handling state, then you should propagate the handleUpdate to the Parent:
此外,我建议您决定是否需要从 Parent 或 Child 管理/更新道具。如果 Parent 负责处理状态,那么您应该将 handleUpdate 传播给 Parent:
//@Parent component
<Child handleUpdate={()=> this.handleUpdate} .../>
//@Child component
handleUpdate = () => {
this.props.handleUpdate
}
You shouldn't be required to use any other function (in React 16+) for managing props from child to parent and vice versa.
你不应该被要求使用任何其他函数(在 React 16+ 中)来管理从子级到父级的道具,反之亦然。
Usually these "bidirectional" cases are structure "smells" and signify that the separation of concernsfor each component has been misadjusted or has not been fully figured out yet.
通常,这些“双向”情况是结构“气味”,表示每个组件的关注点分离已被错误调整或尚未完全弄清楚。