Code Monkey home page Code Monkey logo

next-frame's Introduction

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

next-frame's People

Contributors

corbt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

next-frame's Issues

User input is blocked

Hi! Thanks for this library and the wonderful blog post.

I have wrapped my data loading using next-frame, something like this:

async loadData() { 
    ...get contentArray from database...

    await Promise.all(contentArray.map(async (item) => { 
            await nextFrame(); 
            ...do some stuff with item...
    }));

    ...do some more stuff...
}

It sure prevented the GUI rendering from being blocked while the data loads, but for some reason the GUI doesn't respond to any input (pressing buttons etc) until the loadData method has finished. Do I do something wrong or is this just the way it is?

Update:
Just out of curiosity, I put like ten await nextFrame(); in there, and then the GUI got more responsive, even if the data loading obviously took a lot longer to finish.

Why not InteractionManager.runAfterInteractions?

Hi @corbt ๐Ÿ‘‹

I like your idea, but I have a question.

Why is your logic based on requestAnimationFrame rather than InteractionManager.runAfterInteractions. React Native doc says

requestAnimationFrame(): for code that animates a view over time.
runAfterInteractions(): run code later, without delaying active animations.

Please explain this bit

In Readme,

let recordingsJSON = await response.json();

for (let recording of recordingsJSON) {
... }

Isn't recordingsJSON just a plain object at this point? How is it iterable with for...of ?

Maybe use something like: Object.entries(recordingsJSON)

Rendering a collection of components one frame at a time.

What if you have an array of objects and want to map through the array, then use the object properties as component props so that each component renders one frame at a time? Is that possible with this module? It seems that I can manipulate data with this module one frame at a time, but rendering a component one frame at a time would not work. Please correct me if I'm wrong.

The issue I have is that once a TouchableOpacity is clicked to render all these components, the rendering makes the TouchableOpacity animation really slow. So I would like to split up the rendering of these components over multiple frames.

Help to use nextFrame with Redux Saga

Hie,
I'm using axios in Redux saga.
While calling multiple APIs, User Interaction freezes until got response from all called APIs.
Can nextFrame() help me to resolve freezing issue?
If yes then where can I use this method?
In Saga file or anywhere else ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.