javascript - How to setState in a onTick event that ticks every millisecond - Stack Overflow

I'm trying to set a state in an onTick event for a clock.<Viewer><ClockstartTime={start.c

I'm trying to set a state in an onTick event for a clock.

 <Viewer>
   <Clock
        startTime={start.clone()}
        stopTime={stop.clone()}
        currentTime={start.clone()}
        multiplier={50}
        onTick={_.throttle(handleValue, 1000)} // this thing ticks every millisecond
      />
    <Entity
          ref={ref} // here is the ref to get the value I want to set state with
          position={positionProperty}
          tracked
          selected
          model={{ uri: model, minimumPixelSize: 100, maximumScale: 100.0 }}
          availability={
            new TimeIntervalCollection([
              new TimeInterval({ start: start, stop: stop }),
            ])
          }
        />
 </Viewer>

Here is the handleValue function.

  const handleValue = (clock) => {
//setting the state here ( I want to display the chaning the value over time) 
  setHeadingValue(ref.current.cesiumElement._properties._heading.getValue(clock.currentTime));
    }
  };

The problem is it looks like it tries to re-render over and over which freezes the app. Due to the nature of setState, this behavior makes sense. But I feel like there is an answer that's escaping me. May I have some insight as to what I could do? I'm out of ideas. I'm using Resium ( a react library) and right now I'm setting the value using .getElementByID() and appending to the dom.. which defeats using react in the first place...

Here is a code sandbox: =/src/ViewerComponent.js

Some elements are not showing because we need a token, but that does not affect the functionality I'm looking for. Just open the console of the code sandbox and go to the ViewerComponent.js

thank you for your help

I'm trying to set a state in an onTick event for a clock.

 <Viewer>
   <Clock
        startTime={start.clone()}
        stopTime={stop.clone()}
        currentTime={start.clone()}
        multiplier={50}
        onTick={_.throttle(handleValue, 1000)} // this thing ticks every millisecond
      />
    <Entity
          ref={ref} // here is the ref to get the value I want to set state with
          position={positionProperty}
          tracked
          selected
          model={{ uri: model, minimumPixelSize: 100, maximumScale: 100.0 }}
          availability={
            new TimeIntervalCollection([
              new TimeInterval({ start: start, stop: stop }),
            ])
          }
        />
 </Viewer>

Here is the handleValue function.

  const handleValue = (clock) => {
//setting the state here ( I want to display the chaning the value over time) 
  setHeadingValue(ref.current.cesiumElement._properties._heading.getValue(clock.currentTime));
    }
  };

The problem is it looks like it tries to re-render over and over which freezes the app. Due to the nature of setState, this behavior makes sense. But I feel like there is an answer that's escaping me. May I have some insight as to what I could do? I'm out of ideas. I'm using Resium ( a react library) and right now I'm setting the value using .getElementByID() and appending to the dom.. which defeats using react in the first place...

Here is a code sandbox: https://codesandbox.io/s/resium-cesium-context-forked-bpjuw?file=/src/ViewerComponent.js

Some elements are not showing because we need a token, but that does not affect the functionality I'm looking for. Just open the console of the code sandbox and go to the ViewerComponent.js

thank you for your help

Share Improve this question edited May 10, 2021 at 20:06 Esther Cuan asked May 9, 2021 at 4:26 Esther CuanEsther Cuan 3873 silver badges19 bronze badges 11
  • what behaviour are you trying to achieve? I mean you want to set value and not re-render ponent? But how do you want to use that value? – Dmytro Krasnikov Commented May 9, 2021 at 4:43
  • Are you saying that this Clock ponent implements some interval with a 1ms delay, and this is too many updates so you are trying to throttle this callback? Most browsers enforce a 4ms minimum interval/timer delay, and React tries to run a UI at 60 frames/second, which is about 17ms per render cycle, so trying to do anything faster than this is basically waste. If you are running a clock ponent why not just use an interval delay that matches the smallest interval you care about, which seems to be the 1 second throttling? – Drew Reese Commented May 9, 2021 at 6:07
  • Thank you @DrewReese! The Cesium library for react is called Resium. They are the ones who provide the clock ponent: resium.darwineducation./ponents/Clock I need to use the onTick event from that Clock to get the value as time goes by. Im trying to display a property in the UI that changes as time passes, like a car that is driving and the current speed. I want to save that speed in state but if I set state in the onTick event, the whole Cesium ponent tries to re-render. I have tried throttle and the Cesium map still freezes :( – Esther Cuan Commented May 9, 2021 at 6:25
  • Woah, that's a pretty cool library. Thank you for the extra details. There was a quite a bit to digest from the docs. Think you could create and provide us a running codesandbox that reproduces the issue that we could live debug? – Drew Reese Commented May 9, 2021 at 7:22
  • Who is rendering <Clock /> ? Need an overview of who's rendering who aka ponent hierarchy. – Badal Saibo Commented May 9, 2021 at 7:27
 |  Show 6 more ments

3 Answers 3

Reset to default 5 +50

As I see, the problem here not in the library, but in a way of managing calculation and visualization.

As few people already mentioned, for UI, user don't need more than 60fps, but for process sometimes we need more.

So the solution is to separate processing from visualization.

To be more generic, here is an example in pure JavaScript:

// Here it may be some ponent 
const clockView = document.getElementById('speedyClock')

let state = null
// This function mimicking dispatch on state update 
function setState(val) {
  state = val
  clockView.innerHTML = state
} 

const FPS = 30


// Any state out of visualization scope
// Not the React state!!!
let history = []

let nextUiUpdate = Date.now()+(1000/FPS) 

/// Super speedy process
setInterval(function() {
  history.push(Math.random())
  const now = Date.now()
  
  // Update according to visual frame rate
  if(now >= nextUiUpdate) {
    // Prepare visual updates
    setState(JSON.stringify({count: history.length, history}, null, 2))
    history = []    
    nextUiUpdate = Date.now()+(1000/FPS)
  }
}, 1)
<pre id="speedyClock"></pre>

I would suggest using requestAnimationFrame, instead of setInterval as their is no point rerendering the React tree more than once every screen refresh.

By using a bination of shouldComponentUpdate and setState you can effectively setState and prevent unnecessary renders.

This is my codesandbox url to show it.

You can access your wanted value as often as you want, but we need to prevent 1 render per millisecond with shouldComponentUpdate function.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744385836a4571656.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信