当父级的状态更改时,如何在React中更新(重新渲染)子级组件?

时间:2019-11-23 09:19:39

标签: javascript reactjs react-props react-component react-state

好的,我已经知道一种方法。但是,我是在问这个问题,以防我重新发明轮子,因为我是React的新手。我的印象是,如果父组件通过道具将其状态传递给子组件,而不是更新父组件的状态,则子组件将在需要时重新渲染。但这似乎并非如此。我设置了这个示例,

class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: props.number,
    };
  }

  updateNumber(n) {
    this.setState({number: n});
  }

  render() {
    return (<h1>{this.state.number}</h1>);
  }
}

class Parent extends Component {

  constructor(props) {
    super(props);
    this.state = {
      number: -1,
    };
    this.child = React.createRef();
    setInterval(this.updateState.bind(this), 1000);
  }

  updateState() {
    console.log(this.state);
    this.setState({
      number: Math.floor((Math.random() * 10) + 1),
    });
    // this.child.current.updateNumber(this.state.number);
  }

  render() {
    return (
      <div>
        <Child ref={this.child} number={this.state.number}/>
      </div>
    );
  }
}

在此示例中,除非我明确定义引用并使用它来调用子级的update函数(注释部分),否则不会在每次更新父级状态时重新渲染子级。就是这样吗?如果您要手动更新孩子的状态(heh),或者如果他们的父母的状态作为道具传递给孩子,他们是否应该自动更新(并因此重新渲染)。

3 个答案:

答案 0 :(得分:2)

这是因为您的Child组件也正在使用其自己的状态。总是问自己state是否必要,这是React初学者的常见错误。

希望您可以通过查看此示例来进一步了解它。建议您不要在构造函数中调用setInterval,而建议在componentDidMount中调用它,而在componentWillUnmount中调用clearInterval

// Since you are not using state, you can use functional component for your Child component
const Child = ({ number }) => <h1>{number}</h1>;

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.timer = null;
    this.state = { number: 0 };
  }

  componentDidMount() {
    // setInterval after component did mount
    this.timer = setInterval(this.incrementNumber, 1000);
  }

  componentWillUnmount() {
    // clearInterval when component is going to unmount
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  incrementNumber = () => {
    // setState function callback to ensure state received will be latest state
    this.setState(prevState => ({ number: prevState.number + 1 }));
  }

  render() {
    const { number } = this.state;
    return (
      <div>
        <Child number={number} />
      </div>
    );
  }
}

答案 1 :(得分:1)

您的方法是错误的,不要像这样从子级更新您的父级状态,也不要将道具在子级中保存,因为它们已随着父级更新而更新。

如果您想更新父级表单子级,则将道具表单子级传递给父级。当父级更新子级也将更新时。

class Child extends Component {
  constructor(props) {
    super(props);
  }

updateNumber=()=>{// update parent form child. call this function in somewhere in your component. if you want to pass event pass it as second argument
  this.props.updateNumber(newUpdatedNumber,event);
}

  render() {
    return (<h1>{this.props.number}</h1>);
  }
}

class Parent extends Component {

  constructor(props) {
    super(props);
    this.state = {
      number: -1,
    };
    this.child = React.createRef();
    setInterval(this.updateState.bind(this), 1000);
  }

  updateState() {
    console.log(this.state);
    this.setState({
      number: Math.floor((Math.random() * 10) + 1),
    });
  }
//update parent from child

  updateParentFromChild=(updatedNumber,event)=>{//catch function from child 
   this.setState({
      number:updatedNumber
   });
  }


  render() {
    return (
      <div>
        <Child ref={this.child} updateNumber={this.updateParentFromChild} number={this.state.number}/>
      </div>
    );
  }
}

答案 2 :(得分:0)

重新渲染孩子的一个简单选择是每次需要重新渲染时都更新唯一的键属性。

C:\Program Files\dotnet\sdk\3.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(234, 5): error NETSDK1064: Package Microsoft.CodeAnalysis.Analyzers, version 2.9.3 was not found. It might have been deleted since NuGet restore. Otherwise, NuGet restore might have only partially completed, which might have been due to maximum path length restrictions. [C:\Program Files (x86)\Jenkins\workspace\test\ProductCoreApi\ProductCoreApi.csproj]