【问题标题】:React Child Component Not Updating After Parent State Change父状态更改后反应子组件未更新
【发布时间】:2017-05-05 03:30:44
【问题描述】:

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

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

我错过了什么吗?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    您的代码有两个问题。

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

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

    引用此SO Answer

    将初始状态作为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/

    【讨论】:

    • "如果你知道自己在做什么,initialize state based on props 没关系" 除了 nextProp 不会在没有 @ 的情况下触发重新渲染之外,通过 prop 设置状态还有其他缺点吗987654336@?
    • 据我所知,没有其他缺点。但是在您的情况下,我们可以清楚地避免在子组件中存在状态。父级可以将数据作为道具传递,当父级使用其新状态重新渲染时,子级也将重新渲染(使用新道具)。实际上,这里不需要在 child 内部保持状态。纯组件 FTW!
    • 对于从现在开始阅读的任何人,请查看static getDerivedStateFromProps(nextProps, prevState)reactjs.org/docs/…
    • 除了 componentWillReceiveProps() 因为它现在已被弃用,还有其他解决方案吗?
    • @LearningMath 请参阅最新的React docs,其中谈到了替代方法。您可能需要重新考虑您的逻辑。
    【解决方案2】:

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

    例如:-

    在这里,我将在我的状态下更改一组对象的一个​​属性,看看我如何将所有数据分散到一个新对象中。另外,下面的代码对你来说可能有点陌生,它是一个 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} 
            })
        } 
    

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

    【讨论】:

      【解决方案3】:

      有些事情你需要改变。

      fetch得到响应时,不是json。 我一直在寻找如何获得这个 json,我发现了这个 link

      另一方面,你需要认为constructor函数只被调用一次。

      因此,您需要更改在&lt;Child&gt; 组件中检索数据的方式。

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

      希望对你有帮助。

      【讨论】:

      • 谢谢。虽然,看看你做的例子,似乎 Child 永远不会更新。有关如何更改 Child 接收数据的方式的任何建议?
      • 你确定吗?我看到 &lt;Child&gt; 组件从 https://jsonplaceholder.typicode.com/posts/1 检索新数据并重新渲染。
      • 是的,我看到它现在可以在 OSX 上运行。 iOS 没有触发 StackExchange 应用浏览器中的重新渲染
      猜你喜欢
      • 2021-07-07
      • 2021-03-31
      • 1970-01-01
      • 2021-07-17
      • 2019-12-23
      • 2019-07-12
      • 1970-01-01
      • 2017-09-10
      • 2018-11-03
      相关资源
      最近更新 更多