即使数据没有改变,我可以用 setState 强制重新渲染吗?我的 GUI 不会更新?
Posted
技术标签:
【中文标题】即使数据没有改变,我可以用 setState 强制重新渲染吗?我的 GUI 不会更新?【英文标题】:Can I force a rerender with setState even if the data hasn't changed? My GUI won't update? 【发布时间】:2017-10-16 07:48:12 【问题描述】:所以我现在遇到的问题是在第一次点击时,我的 GUI 会重新渲染。但在第二次点击时,它不会重新渲染。我相信这是因为我没有更新我的渲染通过“graphicLayers.map”绑定的“graphicLayers”的状态。无论如何,这是我的理论(即使它适用于第一次点击?但不是第二次点击或之后的任何东西)。
我尝试强制对图形图层进行 setState 更新,但它似乎不起作用。像这样:
let graphicLayersCopy = Object.assign([], this.state.graphicLayers);
this.setState(graphicLayers: graphicLayersCopy);
但这不起作用。我通过调试器知道它正确设置了数据,如果我刷新(它保存状态并重新加载状态),那么 GUI 就会正确呈现。
无论如何我可以强制重新渲染一个变量,即使它不改变值?
构造函数
constructor(props, context)
super(props, context);
this.state =
graphicLayers: [id1, id2, id3],
graphicLayersById:
id1: ... ,
id2: ... ,
id3: ...
this.addLayerClick = this.addLayerClick.bind(this);
;
渲染
render()
return (
<div>
this.state.graphicLayers.map((id) =>
<GraphicLayer addLayerClick=this.addLayerClick.bind(this) />
)
</div>
);
添加图层点击
addLayerClick()
... change some property in graphicLayersById dictionary ...
self.setState( graphicLayersById: newDataHere );
编辑:我发现了我的问题,这里没有完全显示。
所以我的 addLayerClick() 实际上调用了另一个正在监听调用的函数,它设置了内部的状态。这很奇怪,因为 setState 在回调函数中被调用,但我通过将 setState 放入 addLayerClick() 本身来让它工作.. 仍然不知道为什么这不起作用,但我至少会支持你们所有人
listenFunction()
let self = this;
this.firebaseWrapper.storage.on('graphicLayersById', function (save)
if (save)
self.setState( graphicLayersById: save ); // FOR SOME REASON THIS DOESN'T UPDATE THE GUI THE 2nd CLICK. The data is correct though and I see it going here on a breakpoint, but GUI won't update unless I setState in the actual button
else
self.setState( graphicLayersById: undefined );
);
【问题讨论】:
.bind(this) 写了两次。 @TreefishZhang 嘿,感谢您的评论。我实际上补充说,当我发现问题希望它会起作用时..我只是根据您的评论将其删除并将其留在构造函数中,但不幸的是仍然存在同样的问题 在'仍然不知道为什么这不起作用':我的直觉是你应该在你所说的组件的包装组件中的 handleAddLayerClick() 函数中执行 setState,然后将函数传递给您所说的组件,您不再执行 setState,只需 render()。 @TreefishZhang 多亏了一位朋友,我才真正找到了问题所在。我的 GraphicLayer 组件实际上是接收到的道具并将其存储到 GraphicLayer 组件的状态。所以我一直在谈论的 setState 是在 home 组件上,并没有渲染 GrahpicLayer 状态。这首先是愚蠢的。我从 GraphicLayer 组件中完全删除了状态,只使用了道具(因为我从我的主组件中传递了 click 函数)并且它工作得很好。 哦,所以我认为'home'组件是'GraphicLayer'的父组件?这是有道理的:当通过 'home' 中的 setState 更改状态时,这些更改会传递给子组件 'GraphicLayer' 并被渲染。当 props 发生变化时,React 有义务重新渲染。 【参考方案1】:在addLayerClick()
中,您只更新graphicLayersById
,但渲染取决于graphicLayers
。您还应该更新addLayerClick()
中的graphicLayers
状态。
addLayerClick()
this.setState(
graphicLayers: ...
graphicLayersById: ....
);
附带说明,您不应该在 render()
中绑定方法,因为这会在每次渲染时创建一个全新的函数(并且可能会影响性能)。而不是
<GraphicLayer addLayerClick=this.addLayerClick.bind(this) />
做
<GraphicLayer addLayerClick=this.addLayerClick />
并将绑定保留在您的构造函数中(您已经拥有的方式)。
【讨论】:
【参考方案2】:其实你已经给组件绑定了addLayerClick()
函数,所以你可以用this
代替self
您应该像这样修改您的代码:(大约有 2 处更改)
constructor(props, context)
super(props, context);
this.state =
graphicLayers: [id1, id2, id3],
graphicLayersById:
id1: ... ,
id2: ... ,
id3: ...
// don't need to bind here anymore, since you bind it in the click
//this.addLayerClick = this.addLayerClick.bind(this);
;
addLayerClick()
//... change some property in graphicLayersById dictionary ...
// just use 'this' here
this.setState( graphicLayersById: newDataHere );
// the below line is NOT recommended, which is force the component to update
// this.forceUpdate(); // this line will update the component even though there's no change
如果这还不起作用,请在此处发布您如何处理子组件中的onCLick
函数,如果有错误,请在此处发布,谢谢
【讨论】:
【参考方案3】:希望这两种可能的方式会重新审视你的观点
this.setState(graphicLayersById: newDataHere , ()=>
console.log(this.state.graphicLayersById);
);
或
var update = require('react-addons-update');
var graphicLayers = update(this.state,
graphicLayersById: $set: newDataHere
);
this.setState(graphicLayers);
【讨论】:
以上是关于即使数据没有改变,我可以用 setState 强制重新渲染吗?我的 GUI 不会更新?的主要内容,如果未能解决你的问题,请参考以下文章