【问题标题】:Updating state with props on React child component在 React 子组件上使用 props 更新状态
【发布时间】:2017-01-02 10:59:00
【问题描述】:

我有一个 React 应用程序,其中来自父组件的 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>
    }
}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    你需要在你的孩子身上实现componentWillReceiveProps

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

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

    【讨论】:

    • 你知道那些时候你只想对随机的 SO 海报说“我爱你”,这就是其中之一。谢谢好心人。
    • 整天都在找这个!尝试将状态更新为子级,并且这样做了
    • 已经2018年了,不知道根据react官方文档更新这个答案好不好。 componentWillReceiveProps 将来会被弃用,他们建议改用 componentDidUpdate 之类的东西。
    • 谢谢,为此添加了注释。
    【解决方案2】:

    有几件事。至少可以说,您在单击时绑定功能的方式是不寻常的。我建议您要么在构造函数上执行此操作,要么改用箭头函数(这会自动将函数绑定到类)。

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

    此外,我建议您决定是否需要从父级或子级管理/更新道具。如果 Parent 负责处理状态,那么您应该将 handleUpdate 传播给 Parent:

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

    您不应该被要求使用任何其他功能(在 React 16+ 中)来管理从孩子到父母的道具,反之亦然。

    通常这些“双向”情况是结构“气味”,表示每个组件的关注点分离已被错误调整或尚未完全弄清楚。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        最好检查一下是否需要更新状态,因为这会导致重新渲染。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-23
          • 1970-01-01
          • 2021-10-09
          • 2015-12-01
          • 1970-01-01
          • 2018-10-09
          • 2020-09-22
          • 1970-01-01
          相关资源
          最近更新 更多