Skip to content

theKashey/react-queue

Repository files navigation

React ⏳ Queue


A declarative scheduler

To schedule events one-after another. To play lazy animations in order, correlated with their position on the page.

API

Scheduler

  • Scheduler - task scheduler. Collect tasks and execute them with stepDelay between in the priority order.
    • stepDelay - delay between two events
    • [reverse] - reverses the queue
    • [source] - priority calculation function
    • [withSideEffect] - indicates that Scheduler has side effects, and enabled auto update(re-render) on task execution. Affects performance.
    • [observe] - cache buster property. Scheduler sorts queue only on element change, in case of using source you might need "inform"
    • [noInitialDelay] - remove delay from the first task.
    • [disabled] - disables ticking it to resort queue.
import {Scheduler} from 'react-queue';

<Scheduler stepDelay={1000} >
  {channel => .... }
</Scheduler>

// use source to create priority based on element position on the page
<Scheduler stepDelay={1000} source={ ({ref}) => ref.getBoundingClientRect().top} />

channel also provides channel.reset() function, to clear all executed bits, and start everything from the scratch.

Queue

  • Queue - queued event. It just got executed, nothing more. "When", in "when order" - that is the question.
    • channel - channel acquired from Scheduler
    • callback - callback to execute. In case if callback will return a number, or a promise resolving to number, it would be used to shift delay to the next step.
    • priority - pririty in queue, where 0-s should be executed before 1-s.
    • [shift] - sub priority change. shift={-1} will swap this task with previous sibling.
    • [disabled] - holds queue execution (sets priority to Infitity). next tick will be moved by {number}ms. In case of just Promise - next tick will wait to for promise to be resolved.
    • [children] - any DOM node, Queue will pass as ref into scheduler's source
import {Scheduler, Queue} from 'react-queue';

<Scheduler stepDelay={1000} >
    {channel => 
      <Queue channel={channel} priority={1} callback={doSomething} />
      
      // this one will report `ref` to the scheduler
      <Queue channel={channel} callback={doSomething}>
        <div>42</div>
      </Queue>  
         
      <Queue channel={channel} callback={() => this.setState({x: 1})}>
        <div style={{position: 'absolute', top: 50}}> 1 {x == 1 && "selected!!"}</div>
      </Queue>

      <Queue channel={channel} callback={() => this.setState({x: 2})}>
        <div style={{position: 'absolute', top: 10}}> 2 {x == 2 && "selected!!"}</div>
      </Queue>

      <Queue channel={channel} callback={() => this.setState({x: 3})}>
        <div style={{position: 'absolute', top: 100}}> 3 {x == 3 && "selected!!"}</div>
      </Queue>
    }
</Scheduler>

FlattenPriorityGroup

  • FlattenPriorityGroup - "flattens" all priority changes inside. Could help manage nested tasks.
    • channel - channel acquired from Scheduler
    • [children] - render function
    • [priority] - task priority. Would be set for all nested tasks.
    • [shift] - sub priority change. shift={-1} will swap this task with previous sibling.
    • [disabled] - holds queue execution (sets priority to Infitity).

In the next example executing order would be - 2, 1, 4, 3.

 <Scheduler stepDelay={1000} >
   {channel => (
      <React.Fragment>
          <FlattenPriorityGroup channel={channel}>
          { pchannel => [
            <Promised priority={1}>1</Promised>,
            <Promised priority={0}>2</Promised>
          ]}
          </FlattenPriorityGroup>
          <FlattenPriorityGroup channel={channel}>
          { pchannel => [
             <Promised priority={1}>3</Promised>,
             <Promised priority={0}>4</Promised>
          ]}
          </FlattenPriorityGroup>
      </React.Fragment>
   )}  
</Scheduler>   

Promised

  • Promised - promised event. Once it started it should all done when it's done. This is a more complex form of queue, with much stronger feedback.
    • channel - channel acquired from Scheduler
    • [children] - render function
    • [autoexecuted] - auto "done" the promised. boolean or number. If number - would be used to shift next step.
    • [priority] - task priority. Lower goes first
    • [shift] - sub priority change. shift={-1} will swap this task with previous sibling.
    • [disabled] - holds queue execution (sets priority to Infitity).
import {Scheduler, Promised} from 'react-queue';
import {Trigger} from 'recondition';

<Scheduler stepDelay={1000} >
    {channel => 
      <Promised channel={channel} priority={1}>
      {({executed, active, done, forwardRed}) => (
        <div ref={forwardRed}>
          {executed && "task is done"}
          {active && "task is running"}
          // don't call anything in render
          <Trigger when={active} then={() => done(42/* make next step by 42ms later*/)}/>
        </div>
      )
      </Promised>      
    }
</Scheduler>

// this code has the same behavior
<Scheduler stepDelay={1000} >
    {channel => 
      <Promised channel={channel} priority={1} autoexecuted={42}>
      {({executed, active, done, forwardRed}) => (
        <div ref={forwardRed}>
          {executed && "task is done"}
          {active && "task is running"}          
        </div>
      )
      </Promised>      
    }
</Scheduler>

For example - animation - it will execute one Promised after another, and triggering waterfall animation.

import {Scheduler, Promised} from 'react-queue';
import {Trigger} from 'recondition';

<Scheduler stepDelay={300} >
    {channel => 
      <Promised channel={channel} autoexecuted>
      {({executed, active, fired}) => (<div style={styles[executed||active ? styleA : styleB}>Line1</div>)}
      </Promised>      
      
      <Promised channel={channel} autoexecuted>
      {({executed, active, fired}) => (<div style={styles[executed||active ? styleA : styleB}>Line2</div>)}
      </Promised>      

      <Promised channel={channel} autoexecuted>
      {({executed, active, fired}) => (<div style={styles[executed||active ? styleA : styleB}>Line3</div>)}
      </Promised>      

      <Promised channel={channel} autoexecuted>
      {({executed, active, fired}) => (<div style={styles[executed||active ? styleA : styleB}>Line4</div>)}
      </Promised>      
    }
</Scheduler>

Examples

react-remock + react-queue - simple and complex example - "jquery like" image lazy loading with queued execution. react-visibility-sensor + react-queue - animate element appearance based on visibility check.

Licence

MIT

Releases

No releases published

Packages

No packages published