Esri / react-arcgis

A few components to help you get started using the ArcGIS API for JavaScript and esri-loader with React
Apache License 2.0
319 stars 79 forks source link

How to access state from the watchUtils callback? #196

Closed slead closed 4 years ago

slead commented 4 years ago

I'm asking the question here as my specific issue relates to React and ArcGIS Server JS API, but the issue may be more generally with esri-loader, or potentially the JS API itself(?)

My goal is to emulate the behaviour on the AirBnb map whereby the "search as I move the map" option changes its label if the option is not selected and the map extent changes. In that case it becomes a button with a manual "search this area" function.

Screen Shot 2020-11-10 at 2 10 05 pm Screen Shot 2020-11-10 at 2 06 42 pm

In order to achieve this I'm using watchUtils and wish to change the option's label via the state. However, I can't access the state from within the watchUtils callback:

  // in the constructor:
  this.state = {
    buttonText: "search as I move the map",
    checkboxStatus: true
  };

  // within the onLoad function:
  loadModules(["esri/core/watchUtils"]).then(([watchUtils]) => {
    watchUtils.whenTrue(view, "stationary", function () {
      // the "this" object is undefined within the callback so I can't
      // access or modify the state
      console.log(this.state.checkboxStatus)
      if (!this.state.checkboxStatus) {
        console.log("Need to change button text")
      }
    })
  });

Expected behavior How can I access the app's state from within the watchUtils callback?

Actual behavior The this object is undefined inside the callback so the state cannot be accessed or changed.

To Reproduce

Here is a simple example: https://codesandbox.io/s/watchutils-to-state-forked-ipn4o?file=/src/index.js

Versions (please complete the following information):

slead commented 4 years ago

Never mind, I figured it out - passing the watchUtils response/promise to a separate function worked:

  afterMapMove(evt) {
    if (!this.state.checkboxStatus) {
      this.setState({ buttonText: "Search this area" });
    } else {
      this.setState({ buttonText: "Search as I move the map" });
    }
  }

  handleMapLoad(map, view) {
    this.setState({ map: map, view: view });
    loadModules(["esri/core/watchUtils"]).then(([watchUtils]) => {
      watchUtils.whenTrue(view, "stationary", this.afterMapMove);
    });
  }