在React子组件中使用props更新状态

52

我有一个React应用,在其中从父组件传递props到子组件,然后这些props设置了子组件上的状态。

当我向父组件发送更新后的值时,子组件没有使用更新后的props更新状态。

我该如何让它更新子组件上的状态?

我的精简代码:

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>
    }
}
4个回答

72

你需要在子组件中实现 componentWillReceiveProps

componentWillReceiveProps(newProps) {
    this.setState({name: newProps.name});
}

编辑: componentWillReceiveProps 现在已弃用并将被删除,但在上面的文档链接中有替代建议。


9
你知道有些时候,你只是想对一个随机的 SO(significant other)帖子说“我爱你”,现在就是这样的时候。谢谢你,善良的人。 - markau
1
整天都在寻找这个!试图将状态更新到子级,这样做了。 - William
4
已经是2018年了,我不知道是否应该根据React官方文档更新这个答案。componentWillReceiveProps将来会被弃用,他们建议使用类似componentDidUpdate这样的内容替代。 - carloscarcamo
谢谢,已经添加了相关的注释。 - Blorgbeard

8

componentWillReceiveProps中调用setState()不会导致额外的重新渲染。接收props是一次渲染,如果在componentDidUpdate这样的方法中执行了this.setState,那么它将是另一个渲染。我建议在shouldComponentUpdate中执行this.state.name !== nextProps.name,以便始终检查任何更新。

componentWillReceiveProps(nextProps) {
    this.setState({name: nextProps.name});
}

shouldComponentUpdate(nextProps) {
    return this.state.name !== nextProps.name;
}

3

同时,检查一下是否需要更新状态,因为这将导致重新渲染。

componentWillReceiveProps(newProps) {
  if (this.state.name !== newProps.name) {
    this.setState({name: newProps.name});
  }
}

3

有几件事情需要注意。你绑定点击事件的方式非常不寻常。我建议你要么在构造函数中进行绑定,要么使用箭头函数代替(这样会自动将函数绑定到类上)。

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>
    );
  }
}

此外,我建议您决定道具是需要从父组件还是子组件进行管理/更新。如果父组件负责处理状态,则应将handleUpdate传播到父组件:
//@Parent component
<Child handleUpdate={()=> this.handleUpdate} .../>

//@Child component
handleUpdate = () => {
   this.props.handleUpdate
}

在React 16+中,你不需要使用任何其他函数来管理从子组件到父组件和反向传递的props。

通常这些"双向"情况是结构上的"异味",表明每个组件的职责分离已被调整错误或尚未完全解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接