即使数据没有改变,我可以用 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 不会更新?的主要内容,如果未能解决你的问题,请参考以下文章

用 setState 改变状态

React 的setState 理解

this.setState 不起作用(我的状态是一个数字)

react的setState使用中遇到的问题

当setState Flutter时,PageViewer内的小部件没有改变

即使没有更新数据,如何强制 Kendo 网格更新