父状态更改后,React子组件未更新


109

我正在尝试制作一个不错的ApiWrapper组件,以填充各种子组件中的数据。从我阅读的所有内容来看,这应该可以正常工作:https : //jsfiddle.net/vinniejames/m1mesp6z/1/

class ApiWrapper extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      response: {
        "title": 'nothing fetched yet'
      }
    };
  }

  componentDidMount() {
    this._makeApiCall(this.props.endpoint);
  }

  _makeApiCall(endpoint) {
    fetch(endpoint).then(function(response) {
      this.setState({
        response: response
      });
    }.bind(this))
  }

  render() {
    return <Child data = {
      this.state.response
    }
    />;
  }
}

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

  render() {
    console.log(this.state.data, 'new data');
    return ( < span > {
      this.state.data.title
    } < /span>);
  };
}

var element = < ApiWrapper endpoint = "https://jsonplaceholder.typicode.com/posts/1" / > ;

ReactDOM.render(
  element,
  document.getElementById('container')
);

但是由于某种原因,当父状态更改时,子组件似乎没有更新。

我在这里想念什么吗?

Answers:


204

您的代码有两个问题。

您的子组件的初始状态是通过props设置的。

this.state = {
  data: props.data
};

引用此SO答案

将初始状态作为a传递给组件prop是一种反模式,因为getInitialState(在我们的示例中为constuctor)方法仅在组件首次呈现时才调用。再也没有了。这意味着,如果重新渲染该组件并传递一个不同的值a prop,则该组件将不会做出相应的反应,因为该组件将从首次渲染起就保持该状态。这很容易出错。

因此,如果您无法避免这种情况,理想的解决方案是使用该方法componentWillReceiveProps来侦听新道具。

将以下代码添加到子组件将解决子组件重新渲染的问题。

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

第二个问题是fetch

_makeApiCall(endpoint) {
  fetch(endpoint)
    .then((response) => response.json())   // ----> you missed this part
    .then((response) => this.setState({ response }));
}

这是一个有效的小提琴:https : //jsfiddle.net/o8b04mLy/


1
“这没关系基于道具初始化状态,如果你知道你在做什么”是否有任何其他方面的不足通过道具设置状态,事实上,旁边nextProp不会触发一个不重新渲染componentWillReceiveProps(nextProps)
温妮·詹姆斯

11
据我所知,没有其他缺点。但是在您的情况下,我们可以明确避免在子组件内部具有状态。父级仅可以传递数据作为道具,而当父级以其新状态重新渲染时,子级也将重新渲染(具有新的道具)。在这里,实际上不需要维持孩子的状态。纯组件FTW!
Yadhu Kiran

7
对于从现在开始阅读的任何人,请查看static getDerivedStateFromProps(nextProps, prevState) reactjs.org/docs/…–
GoatsWearHats

4
除了componentWillReceiveProps()之外,还有其他解决方案吗,因为现在已弃用了它?
LearningMath

3
@LearningMath请参阅最新的React文档,其中介绍了其他方法。您可能需要重新考虑自己的逻辑。
Yadhu Kiran

1

您需要更改某些内容。

fetch得到的回应,它不是一个JSON。我一直在寻找如何获取这个json,然后发现了这个链接

另一方面,您需要认为该constructor函数仅被调用一次。

因此,您需要更改在<Child>组件中检索数据的方式。

在这里,我留下了一个示例代码:https : //jsfiddle.net/emq1ztqj/

希望对您有所帮助。


谢谢。虽然,看一下您所做的示例,似乎Child从未更新。关于如何更改Child接收数据方式的任何建议?
文妮·詹姆斯

2
你确定吗?我看到该<Child>组件从中检索新数据https://jsonplaceholder.typicode.com/posts/1并重新渲染。
slorenzo '16

1
是的,我认为它现在可以在OSX上运行。iOS并没有在StackExchange应用浏览器中触发重新渲染
Vinnie James
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.