2

So the problem I'm having right now is on first click, my GUI re-renders. But on second click, it does not re-render. I believe it's because I am not updating the state of "graphicLayers" which my render is binding through the "graphicLayers.map". That's my theory anyway (even though it works on first click? but not the 2nd click or anything after).

I tried forcing an setState update of graphicLayers, but it doesn't seem to be working. Like this:

let graphicLayersCopy = Object.assign([], this.state.graphicLayers);
this.setState({graphicLayers: graphicLayersCopy});

but that's not working. I know through the debugger that it's setting the data correctly, and if I refresh (it saves state and reloads the state), the GUI is then rendered correctly.

Is there anyway I can force a re-render of a variable some how even if it doesn't change value?

constructor

constructor(props, context) {
    super(props, context);

    this.state = {
      graphicLayers: [id1, id2, id3],
      graphicLayersById: {
        id1: { ... },
        id2: { ... },
        id3: { ... }
      }

    this.addLayerClick = this.addLayerClick.bind(this);
};

render

render() {
    return (        
    <div>
      {this.state.graphicLayers.map((id) =>
        <GraphicLayer addLayerClick={this.addLayerClick.bind(this)} />
      )}
    </div>
    );
   }

addLayerClick

addLayerClick() {
  ... change some property in graphicLayersById dictionary ...
  self.setState({ graphicLayersById: newDataHere });
}

EDIT: I found the problem on my end, and it's not exactly shown here.

So my addLayerClick() actually calls another functions that is listening to a call and it sets the state inside. it's weird because the setState gets called in the callback function, but i got it to work by putting the setState in the addLayerClick() itself.. still dont know why this doens't work but i will upvote all of you at least

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 });
  }
});

}

4

3 回答 3

3

addLayerClick()你只是更新graphicLayersById,但渲染取决于graphicLayers. 您也应该更新graphicLayers状态addLayerClick()

addLayerClick() {
  this.setState({
    graphicLayers: ...
    graphicLayersById: ....
  });
}

附带说明一下,您不应该在内部绑定方法,render()因为这会在每次渲染时创建一个全新的函数(并且可能会影响性能)。代替

<GraphicLayer addLayerClick={this.addLayerClick.bind(this)} />

<GraphicLayer addLayerClick={this.addLayerClick} />

并将绑定留在您的构造函数中(您已经拥有的方式)。

于 2017-05-17T04:35:29.120 回答
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子组件中的功能,并发布一些错误(如果有),谢谢

于 2017-05-17T03:48:20.440 回答
2

希望这两种可能的方式会改变你的看法

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);
于 2017-05-17T04:01:23.073 回答