Performance

Whenever the range changes, a recalculation of all the item's width and position must be performed.

When performing operations that require a high amount of sequential changes, like zooming in or panning, the resulted re-renders might cause stuttering and frame-drops.

This "frequent change" problem is quite common in reactive frontend applications, and there are multiple solutions to it.

As you are in full control of the range state, you can apply a chosen mechanism of debouncing to the range state.

This will reduce the amount changes registered in the timeline, and in return reduce the amount of renders required when zooming an panning, resulting in a great improvement in performance.

Here are some common solutions:

If you use React 18+, you should make use of the useDeferredValue API.

useDeferredValue is a React Hook that lets you defer updating a part of the UI.

Code Example

function App() {
  const [range, setRange] = useState(DEFAULT_TIMEFRAME);
  const debouncedRange = useDeferredValue(range);
  
  ...
  
  return (
    <TimelineContext
        onDragEnd={onDragEnd}
        onResizeEnd={onResizeEnd}
        range={debouncedRange} // provide the debounced range
        onRangeChanged={setRange}
    >
      <Timeline items={items} rows={rows} />
    </TimelineContext>
  )

🧠 You can still make use of the un-debounced state to render selected components in real-time. For example, you can render the time-axis using the un-debounced state, and render the timeline using the debounced state.

Play around with the live demo, and watch how the timeaxis and the range move asynchronously🔥

Live Example

In this example, You can play around with difference modes and feel the difference between them.

Click here to see the full code

Last updated