Returns a promise that resolves on the next animationFrame
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
__tests__
jest
.gitignore
.watchmanconfig
LICENSE.md
README.md
index.js
package.json

README.md

Introduction

'next-frame' is a small tool intended to make it easier to create performant UIs in React Native. You can read more about the rationale behind it in the blog post introducing it.

React Native and Javascript don't give us access to background threads without writing native code. This means that every computation we execute should ideally take less than 1/60th of a second so it doesn't interfere with animation performance or percieved responsiveness.

Some computations inevitably take longer than this. When they do, React Native gives you a couple of options:

  1. Port the operation to native code and run it in the background.
  2. Use the InteractionManager to run it after animations.

'next-frame' is designed to be a third option. It allows you to break up an expensive computation into smaller parts and run just part of it on each repaint. This maintains the responsiveness of your UI while the computation is still ongoing.

Quick Start

This quick start assumes that you're already familiar with the async and await keywords, which you can read up on here. Async and await are enabled by default in current versions of React Native, so this pattern works in RN out of the box.

import nextFrame from 'next-frame';

let response = await fetch("https://emberall.com/user/1/recordings");
let responseJSON = await response.json();

for (let recording of responseJSON.recordings) {
  await nextFrame(); // The javascript will yield here and not resume execution until the next frame.
  mergeRecordingToLocalDatabase(recording);
}

For the previous example, let's assume that we get several hundred recordings back from the server as an array, and each one takes about 1/100th of a second to process. Normally processing all of them would take several seconds, and would cause unacceptable lag. However, using await nextFrame() we break up our computation and have much better perceived responsiveness.

mapInFrames

In the common case (like the one in the example above) that you just want to iterate over a collection and process one element per frame, we've included a convenience function mapInFrames that does exactly that. Here's the same example, rewritten with mapInFrames:

import { mapInFrames } from 'next-frame';

let response = await fetch("https://emberall.com/user/1/recordings");
let recordingsJSON = await response.json();

await mapInFrames(recordingJSON, mergeRecordingToLocalDatabase);

Easy, and not imperative at all. 😃

Under the hood

next-frame is extremely simple (check out index.js if you don't believe me). It simply wraps Javascript's requestAnimationFrame in a Promise.

Other Uses

This library was developed with React Native in mind and has only been tested there. However, it should work fine in the browser as well.

License

This library and all files contained within are licensed under the BSD 2 clause license found in LICENSE.md