Use and set a component's state within setInterval function

npasqua
创建于
2018-05-02 20:12:18

This is a question, so I apologize if this isn't the best place to ask.
I'm trying to work with a component's internal state within a setInterval function and I know there are some asynchronous problems I need to be aware of. I also know that I can pass setState a function which would help me protect against async problems... but I can't because I need to use the changed state within the setInterval function? Is what I'm doing safe or should I be working a different way around this problem.

I've seen the following that nearly answers my question and am having trouble visualizing / adapting this (or maybe the behavior I have is fine?):
Stackoverflow Answer

sectionTimerHandler = () => {
    const elapsedSectionTimeMs = this.state.elapsedSectionTimeMs + 1000;
    // Do some stuff with elapsedSectionTimeMs
    this.setState({elapsedSectionTimeMs});
}

restartSectionTimer = () => {
    if (this.sectionTimeIntervalId !== 0) {
        window.clearInterval(this.sectionTimeIntervalId);
    }
    this.sectionTimeIntervalId = window.setInterval(this.sectionTimerHandler, 1000);
    this.setState({ elapsedSectionTimeMs: 0 });
}

or would something like the following be better/safer even though I'm using this.state.elapsedSectionTimeMs + 1000 earlier in the function?

 this.setState((prevState: AssessmentState) => {
      return {
          elapsedSectionTimeMs: prevState.elapsedSectionTimeMs + 1000
      };
});
3条回答
poxrud
回复于
2018-05-03 16:10:17
#1

but I can't because I need to use the changed state within the setInterval function

The problem with the way you have it is that your interval function might still have the old state, even though you called setState after. This is because setState is not guaranteed to run right away, and in fact several setStates can even be batched up together. So by the time your interval function runs there could have been many (or none) calls to setState.

Take a look at the setState docs that perfectly explain this.

I also know that I can pass setState a function which would help me protect against async problems

No you need to pass a second, optional function. It will run after the setState actually gets called.

As per docs:

The second parameter to setState() is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.

Hope this helps.

npasqua
回复于
2018-05-03 17:18:48
#2

I think I've got it now -


    restartSectionTimer = () => {
        if (this.sectionTimeIntervalId !== 0) {
            window.clearInterval(this.sectionTimeIntervalId);
        }
        this.sectionTimeIntervalId = window.setInterval(this.sectionTimerHandler, 1000);
        this.setState({ elapsedSectionTimeMs: 0 });
    }

    componentDidUpdate() {
         const elapsedSectionTimeMs = this.state.elapsedSectionTimeMs;
        // use elapsedSectionTimeMs somewhere in here, do not use setState anywhere in here
        //  it will be guaranteed to be updated by 1000 from the prevState
    }

    sectionTimerHandler = () => {
        this.setState((prevState: AssessmentState) => {
            return {
                elapsedSectionTimeMs: prevState.elapsedSectionTimeMs + 1000
            };
        });
    }

Thanks for the clarification, this is a pretty interesting use case. The documentation is good, I just had a hard time wrapping my head around it and plugging the pieces together. Might be a good example to officially put somewhere in case others have the same kind of issue (or don't even know they are doing something wrong).

I'll close (or feel free to close) the question if it's validated that the code in this post is the best practice.

isidrok
回复于
2018-05-19 14:57:24
#3

I'll close (or feel free to close) the question if it's validated that the code in this post is the best practice.

Remember to clear the interval in the componentWillUnmount callback.

当前位于第1页,总计3 条回复

推荐相似问题

Child component correctly deletes parent's state's object entry, but wrong child is unmounted upon re-render

I have an Order component which keeps a Javascript object in this.state.newItems and renders OrderItem components for ea
讨论数 2
react
创建时间:2018-05-02 18:15:57

Why are the Consumer and Provider properties of Consumer?

Is there a higher meaning for 1) Consumer and Provider both being properties of Consumer? 2) And Consumer being of type
讨论数 3
react
创建时间:2018-05-02 18:03:56

Context API bitmask related questions

I'm playing with Context API bitmask feature to bail out unwanted re-render. I have a dynamic model ( a JSON object) as
讨论数 10
react
创建时间:2018-05-02 13:55:21

Hovering on specific element affects other elements

constructor(props) { super(props); this.state = { isHovered: false }; this.handleMenuHover = this.
讨论数 4
react
创建时间:2018-05-02 11:14:42

React Context Consumer as a HOC

Do you want to request a feature or report a bug? feature Which versions of React, and which browser / OS are affected b
讨论数 2
react
创建时间:2018-05-01 14:04:19

The findByType method from react-test-renderer doesn't find ref-forwarding components

Do you want to request a feature or report a bug? Bug What is the current behavior? In tests, if the component passed to
讨论数 3
react
创建时间:2018-05-01 03:41:45

React.js 16 event listeners leak (increase)

Do you want to request a feature or report a bug? bug What is the current behavior? Create a classic counter component (
讨论数 3
react
创建时间:2018-04-30 19:41:52

Consuming Context with a HOC: when root component with provider is rendered multiple times, how to identify correct context to consume at child component level

I am planning to use react context API for my library which exposes a root component R.js. RContext.js export default co
讨论数 4
react
创建时间:2018-04-30 15:21:21

SyntaxError: Expected the "svgName" prop to be a string, What should I do?

I assign a string to svgName, is ok. return ( { BENIF.map((v, k) => { return (<li k
讨论数 3
react
创建时间:2018-04-30 09:54:52

onMouseDown causes splash on real ios browsers

Do you want to request a feature or report a bug? bug What is the current behavior? unexpected grey splash caused by onM
讨论数 10
react
创建时间:2018-04-29 14:27:00