• Stars
    star
    357
  • Rank 116,638 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

☔️ Babel Macros for automatic React Hooks memoization invalidation

Hooks’ Macro

Babel Macros for React Hooks automatic memoization invalidation.

Features

  1. Extracts all references used, and adds them to the inputs array.

  2. Favors strict correctness over performance, but uses safe optimizations:

    1. skips constants and useless memoization keys;

    2. traverses all functions called or referenced, and appends their dependencies too, removing the need for unnecessary useCallback hooks.

  3. By lowering the bar for high correctness, strives to:

    1. make the use of useAutoMemo and useAutoCallback simple and applicable in many more contests;

    2. reduce the overhead of modifying an input’s semantics (for example from a constant to a prop);

    3. reduce to the bare minimum cases of missed inputs — and therefore stale memoizations or effects.

  4. Thoroughly tested: 50+ test cases and 100% code coverage.

Roadmap Help wanted!

  • Create a debug/trace facility to help debugging stale cache, performance issues.
  • Create a escape hatch to signal that a reference should not be part of the inputs array.
  • Identify a rule where we can safely add property accesses to the inputs array. Very important when dealing with refs (ref.current).
  • Bail out on actual constants (such as primitive literals) Update: Done!
  • Warn/error on known non-invariant values (such as literal objects or arrays) — or auto-useAutoMemo them!
  • Create a auto() generic macro to be used with other hooks and APIs with the same signature.

Installation

Requires babel-plugin-macros, which is already configured for you if you are using Create React App v2+.

npm install --dev hooks.macro
yarn add --dev hooks.macro

Usage

Replace:

import { useMemo } from 'react';

function MyComponent({ labels }) {
  const myComputation = useMemo(
    () => labels.map(label => label.toUpperCase()),
    [labels],
  );
}

With:

import { useAutoMemo } from 'hooks.macro';

function MyComponent({ labels }) {
  const myComputation = useAutoMemo(() =>
    labels.map(label => label.toUpperCase()),
  );
}

Or even:

import { useAutoMemo } from 'hooks.macro';

function MyComponent({ labels }) {
  const myComputation = useAutoMemo(labels.map(label => label.toUpperCase()));
}

Full reference

useAutoMemo

Exactly like React’s useMemo but automatically identifies value dependencies.

Can be passed a factory function or directly a value, will convert the latter to a function for you.

import { useAutoMemo } from 'hooks.macro';
useAutoMemo(value);
useAutoMemo(() => value);

Both become:

useMemo(() => value, [value]);

useAutoCallback

Exactly like React’s useCallback but automatically identifies value dependencies.

import { useAutoCallback } from 'hooks.macro';
useAutoCallback(() => {
  doSomethingWith(value);
});

Becomes:

useCallback(() => {
  doSomethingWith(value);
}, [doSomethingWith, value]);

useAutoEffect, useAutoLayoutEffect

They work exactly like their standard React counterpart, but they automatically identify value dependencies.

import { useAutoEffect, useAutoLayoutEffect } from 'hooks.macro';
useAutoEffect(() => {
  doSomethingWith(value);
});

Becomes:

useEffect(() => {
  doSomethingWith(value);
}, [doSomethingWith, value]);

Limitations

To make this work I currently needed to pose some limitations. This could change in the future (PR very welcome).

  1. Only variables created in the scope of the component body are automatically trapped as value dependencies.

  2. Only variables, and not properties’ access, are trapped. This means that if you use obj.prop only [obj] will become part of the memoization invalidation keys. This is a problem for refs, and will be addressed specifically in a future release.

    You can work around this limitation by creating a variable which holds the current value, such as const { current } = ref.

  3. Currently there’s no way to add additional keys for more fine grained cache invalidation. Could be an important escape hatch when you do nasty things, but in that case I’d prefer to use useMemo/useCallback directly.

  4. Only locally defined functions declarations and explicit function expressions (let x = () => {}) are traversed for indirect dependencies — all other function calls (such as xxx()) are treated as normal input dependencies and appended too. This is unnecessary (but not harmful) for setters coming from useState, and not an issue at all if the function is the result of useCallback or useAutoCallback.

Inspiration

React documentation about useMemo and use*Effect hooks cites: (emphasis mine)

The array of inputs is not passed as arguments to the function. Conceptually, though, that’s what they represent: every value referenced inside the effect function should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically.

This project tries to cover exactly that: to create the inputs array automatically.

License

MIT

More Repositories

1

react-use-refs

Hook to create multiple refs in a single call
JavaScript
214
star
2

react-titanium

React custom renderer for Appcelerator® Titanium™ SDK
JavaScript
108
star
3

TiShimmer

Facebook’s Shimmer port for Titanium SDK (iOS and Android)
Python
31
star
4

Beauvoir

Simple project management app built with node.js
JavaScript
11
star
5

ti-htmlparser2

Forgiving HTML/XML parser for Titanium SDK
JavaScript
7
star
6

java-npm-semver

Implementation of the SemVer Specification — strictly follows npm semantics
Java
6
star
7

hyperloop-macros

Sweet.js macros to accelerate Hyperloop development
JavaScript
6
star
8

frontend-resources-osgi

A discussion about OSGi, Liferay and Front-end
6
star
9

frontend-ng-loader-workspace

Liferay Workspace for experiments in bringing SystemJS and packages support to Liferay Portal
JavaScript
5
star
10

cspec-titanium-packagers-support

CSPEC is for adding official packaging (npm) abilities on Titanium
4
star
11

combinatorial-explosion

Combinatorial explosion for arrays and trees
JavaScript
4
star
12

knockback-site

Knockback.js Site proposal
JavaScript
4
star
13

ti-travis-experiments

Some funny experiments!
JavaScript
3
star
14

postcss-color-mod

PostCSS Polyfill for color-mod() — ⚠️ Experimental
JavaScript
2
star
15

svbstantia

Simple substance-powered Node.js blog platform
JavaScript
2
star
16

underscore.behaviour

Behaviours (execution limiters) extension for Underscore.js javascript library
JavaScript
1
star
17

authograph

Artistic JavaScript signatures.
1
star
18

hyperloop-ejs

Appcelerator’s Hyperloop-oriented EJS Syntax
1
star
19

lris-2015-liferay-7-front-end

Liferay 7 Front-end development
HTML
1
star
20

5cript

Markdown like syntax for theater scripts.
JavaScript
1
star
21

overscore

Underscore.js for hipsters
1
star
22

rosetta

1
star
23

liferay-theme-tasks-fixed

JavaScript
1
star
24

metameric.js

A funny chainable-isation utility
CoffeeScript
1
star
25

titanium-platforms

Titanium™ SDK utils for device conditional code
JavaScript
1
star
26

lrbcr-2018-audience-targeting-mocked-service

JavaScript
1
star
27

smc-image-placer

JavaScript
1
star
28

it_IT

Versione italiana del mio blog personale
1
star
29

lris-2016-metaljs-and-isomorphic-frontend

Metal.js, Soy and Isomorphic Front-end
Java
1
star
30

decorators-toolbox

A Toolbox for writing ES7 decorators more easily
JavaScript
1
star
31

ti-cross-ci-experiments

Experiments in the CI land for cross-platform projects
JavaScript
1
star