父状态更改后反应子组件未更新

新手上路,请多包涵

我正在尝试制作一个不错的 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')
);

但由于某种原因,当父状态发生变化时,子组件似乎没有更新。

我在这里错过了什么吗?

原文由 Vinnie James 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

您的代码有两个问题。

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

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

引用此 SO 答案

将初始状态作为 prop 传递给组件是一种反模式,因为 getInitialState (在我们的例子中是构造函数)方法仅在组件第一次渲染时被调用。再也不会了。这意味着,如果您重新渲染该组件并将 不同 的值传递为 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/

原文由 yadhu 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果上述解决方案仍未解决您的问题,我建议您看看如何更改状态,如果您没有返回新对象,那么有时反应会发现新的先前状态和更改后的状态没有区别,它是在更改状态时始终传递新对象是一个好习惯,看到新对象做出反应肯定会重新呈现所有需要访问该更改状态的组件。

例如: -

在这里,我将更改我状态下的一组对象的一个属性,看看我如何将所有数据分散到一个新对象中。另外,下面的代码对你来说可能有点陌生,它是一个 redux reducer 函数,但别担心,它只是一种改变状态的方法。

 export const addItemToCart = (cartItems,cartItemToBeAdded) => {
        return cartItems.map(item => {
            if(item.id===existingItem.id){
                ++item.quantity;
            }
            // I can simply return item but instead I spread the item and return a new object
            return {...item}
        })
    }

只需确保您正在使用新对象更改状态,即使您对状态进行了微小更改,只是将其传播到新对象中然后返回,这也会在所有适当的位置触发渲染。希望这有所帮助。如果我在某个地方错了,请告诉我 :)

原文由 Sarthak Saklecha 发布,翻译遵循 CC BY-SA 4.0 许可协议