父状态更改后反应子组件未更新
Posted
技术标签:
【中文标题】父状态更改后反应子组件未更新【英文标题】: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')
);
但由于某种原因,当父状态发生变化时,子组件似乎没有更新。
我错过了什么吗?
【问题讨论】:
【参考方案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
函数只被调用一次。
因此,您需要更改在<Child>
组件中检索数据的方式。
在这里,我留下一个示例代码:https://jsfiddle.net/emq1ztqj/
希望对你有帮助。
【讨论】:
谢谢。虽然,看看你做的例子,似乎 Child 永远不会更新。有关如何更改 Child 接收数据的方式的任何建议? 你确定吗?我看到<Child>
组件从 https://jsonplaceholder.typicode.com/posts/1
检索新数据并重新渲染。
是的,我看到它现在可以在 OSX 上运行。 ios 没有触发 StackExchange 应用浏览器中的重新渲染以上是关于父状态更改后反应子组件未更新的主要内容,如果未能解决你的问题,请参考以下文章
当提供者组件父状态发生变化时,为啥不能更新子组件中的值(带有反应上下文)?