0

I want to trigger a delay before initiating a state change in react. This will hopefully animate my deck gl graph.

Currently it reloads the page.

I've trioed timeout and interval, neither working as expected. I presume i am missing something either to do with state of to do with how the window methods work.

this is my function

yearOnChange = e => {
    const data = {
        0: jan95,
        1: jan00,
        2: jan05
    };
    window.setTimeout(
        this.setState({
            location: data[e.currentTarget.value],
            year: e.currentTarget.value
        }),
        10000
    );
};

This is activated byt the function being passed to a child component and then being triggered with an onClick from a button.

I expected a delay to happen, then the state to change.

I am not pretending to know if this is correct code, the best practice or the right way to go about it. It is a new area for me and looking for best practice/solutions.

Can edit code if needed.

UPDATE:

Added the whole code for review to help.

As for when its being called it is simply being passed to a button and an onClick event being fired by that button.

import React, { Component } from "react";
import { StaticMap } from "react-map-gl";
import { H3HexagonLayer } from "@deck.gl/geo-layers";
// import { HexagonLayer } from "@deck.gl/aggregation-layers";
import DeckGL from "@deck.gl/react";
import { jan95, jan00, jan05 } from "../../dummyData/concatData";
// import testData from "../../dummyData/testDataHexNo3.json";
import YearSelector from "../YearSelector/YearSelector";

const MAPBOX_TOKEN =
    "pk.eyJ1Ijoiam5hbGV4YW5kZXIxMCIsImEiOiJjaWlobnE4eGswMDFld2RtNmZxMDl3Nzc3In0.UTaIFjrs21qB1npSeliZbQ";

const mapStyle =
    "mapbox://styles/jnalexander10/cj0xo73a300rr2rta4ny2bj0d/draft/";

const INITIAL_VIEW_STATE = {
    longitude: 0.1278,
    latitude: 51.5074,
    zoom: 7,
    minZoom: 5,
    maxZoom: 10,
    pitch: 50,
    bearing: -27.396674584323023
};

const elevationScale = { min: 0, max: 10 };

class FirstMap extends Component {
    constructor(props) {
        super(props);
        this.state = {
            location: "",
            year: 0,
            elevationScale: elevationScale.min
        };

        this.startAnimationTimer = null;
        this.intervalTimer = null;

        this._startAnimate = this._startAnimate.bind(this);
        this._animateHeight = this._animateHeight.bind(this);
    }

    componentDidMount() {
        this.setState({
            location: jan95
        });

        this._animate();
    }

    _animate() {
        this._stopAnimate();

        // wait 1.5 secs to start animation so that all data are loaded
        this.startAnimationTimer = window.setTimeout(this._startAnimate, 3500);
    }

    _startAnimate() {
        this.intervalTimer = window.setInterval(this._animateHeight, 20);
    }

    _stopAnimate() {
        window.clearTimeout(this.startAnimationTimer);
        window.clearTimeout(this.intervalTimer);
    }

    _animateHeight() {
        if (this.state.elevationScale === elevationScale.max) {
            this._stopAnimate();
        } else {
            this.setState({ elevationScale: this.state.elevationScale + 1 });
        }
    }

    _layerRendering = () => {
        const stateLocation = this.state.location;
        const valuesOfState = stateLocation[0];
        return [
            new H3HexagonLayer({
                id: "h3-hexagon-layer",
                data: valuesOfState && Object.values(valuesOfState),
                pickable: true,
                opacity: 0.15,
                wireframe: true,
                filled: true,
                extruded: true,
                elevationScale: this.state.elevationScale,
                coverage: 50,
                getHexagon: d => d.h3Location,
                getFillColor: [223, 25, 149], // fluorescent pink
                getElevation: d => {
                    console.log("d.price", d.price * 0.5);
                    return Number(d.price / 10);
                }
            })
        ];
    };

    // newData = testData;

    // newData = eval(testData);
    // _layer = new HexagonLayer({
    //  id: "hexagon-layer",
    //  data: testData,
    //  pickable: true,
    //  extruded: true,
    //  radius: 200,
    //  elevationScale: 100,
    //  // upperPercentile: 100,
    //  // getElevationValue: d =>
    //  getPosition: d => d.COORDINATES
    // });

    dataStateChange = () => {
        window.setTimeout(
            this.setState({
                year: jan00
            }),
            2000
        );
        window.setTimeout(
            this.setState({
                year: jan05
            }),
            8000
        );
    };

    // yearOnChange = e => {
    //  const data = {
    //      0: jan95,
    //      1: jan00,
    //      2: jan05
    //  };
    //  window.setTimeout(() => {
    //      this.setState({
    //          location: data[e.currentTarget.value],
    //          year: e.currentTarget.value
    //      });
    //  }, 10000);
    // };

    yearOnChange = e => {
        e.stopPropagation();
        e.nativeEvent.stopImmediatePropagation();
        const data = {
            0: jan95,
            1: jan00,
            2: jan05
        };
        window.setTimeout(
            () =>
                this.setState({
                    location: data[e.currentTarget.value],
                    year: e.currentTarget.value
                }),
            10000
        );
    };

    render() {
        return (
            <div
                style={{
                    display: "flex",
                    justifyContent: "center",
                    alignItems: "center"
                }}
            >
                <YearSelector
                    yearOnChange={this.yearOnChange}
                    year={this.state.year}
                    dataStateChange={this.dataStateChange}
                />
                <DeckGL
                    // layers={this._layer}
                    layers={this._layerRendering()}
                    initialViewState={INITIAL_VIEW_STATE}
                    controller={true}
                >
                    <StaticMap
                        reuseMaps
                        mapStyle={mapStyle}
                        MapController
                        preventStyleDiffing={true}
                        mapboxApiAccessToken={MAPBOX_TOKEN}
                    />
                </DeckGL>
            </div>
        );
    }
}

export default FirstMap;

MittenMits
  • 59
  • 10

2 Answers2

2

The problem is that your calling setState instead of giving setTimeout a function. This is what you're looking for:

yearOnChange = e => {
    const data = {
        0: jan95,
        1: jan00,
        2: jan05
    };
    window.setTimeout(
        () => this.setState({
            location: data[e.currentTarget.value],
            year: e.currentTarget.value
        }),
        10000
    );
};
Jeff Wooden
  • 5,339
  • 2
  • 19
  • 24
  • It's still causing the reload – MittenMits Sep 11 '19 at 16:32
  • If the reload is still happening then I imagine it's not a result of the `setState` call in the `yearOnChange` method. Perhaps you just need to stop event propagation, it's hard to tell without seeing more code. Try the answer here and put it at the beginning of `yearOnChange`: https://stackoverflow.com/questions/36316846/react-onclick-and-preventdefault-link-refresh-redirect – Jeff Wooden Sep 11 '19 at 16:40
  • Added all the code as it is still causing the issues. – MittenMits Sep 11 '19 at 16:54
  • You're not passing a function to the two setTimeout calls in `dataStateChange`. Instead, setState is called immediately, perhaps that somehow affects the refresh due to code elsewhere? Fix those calls and put some console.logs in your setTimeout and perhaps before to get a picture of what's happening. – Jeff Wooden Sep 11 '19 at 17:20
  • Unrelated, your calling clearTimeout on an interval further up in the code, use `clearInterval` – Jeff Wooden Sep 11 '19 at 17:21
0

I found the reason for my issues.

I had placed the button that called the timeout inside a form. Every time the button was being pressed it caused a submission, i presume, which caused the page to refresh. (Again, this is a presumption, i am unsure if this is the reason.)

MittenMits
  • 59
  • 10