JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 233107
  • Score
    100M100P100Q168013F
  • License MIT

Intuitive magical memoization library with Proxy and WeakMap

Package Exports

  • proxy-memoize

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (proxy-memoize) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

proxy-memoize

CI npm size

Intuitive magical memoization library with Proxy and WeakMap

Introduction

In frontend framework like React, object immutability is important. JavaScript itself doesn't support forcing immutability. Several libraries help encouraging immutable coding style, like immer. While immer helps updating an object, this library helps creating a derived value from an object, a.k.a. selector.

This library utilizes Proxy and WeakMap, and provides memoization. The memoized function will re-evaluate the original function only if the used part of argument (object) is changed. It's intuitive in a sense and magical in another sense.

Install

npm install proxy-memoize

How it behaves

import memoize from 'proxy-memoize';

const fn = memoize(x => ({ sum: x.a + x.b, diff: x.a - x.b }));

fn({ a: 2, b: 1, c: 1 }); // ---> { sum: 3, diff: 1 }
fn({ a: 3, b: 1, c: 1 }); // ---> { sum: 4, diff: 2 }
fn({ a: 3, b: 1, c: 9 }); // ---> { sum: 4, diff: 2 } (returning a cached value)
fn({ a: 4, b: 1, c: 9 }); // ---> { sum: 5, diff: 3 }

fn({ a: 1, b: 2 }) === fn({ a: 1, b: 2 }); // ---> true

Usage with React Context

Instead of bare useMemo.

const Component = (props) => {
  const [state, dispatch] = useContext(MyContext);
  const render = useCallback(memoize(([props, state]) => (
    <div>
      {/* render with props and state */}
    </div>
  )), [dispatch]);
  return render([props, state]);
};

const App = ({ children }) => (
  <MyContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </MyContext.Provider>
);

Usage with React Redux

Instead of reselect.

import { useSelector } from 'react-redux';

const getScore = memoize(state => ({
  score: heavyComputation(state.a + state.b),
  createdAt: Date.now(),
}));

const Component = ({ id }) => {
  const { score, title } = useSelector(useCallback(memoize(state => ({
    score: getScore(state),
    title: state.titles[id],
  })), [id]));
  return <div>{score.score} {score.createdAt} {title}</div>;
};

Usage with Zustand

For derived values.

import create from 'zustand';

const useStore = create(set => ({
  valueA,
  valueB,
  // ...
}));

const getDerivedValueA = memoize(state => heavyComputation(state.valueA))
const getDerivedValueB = memoize(state => heavyComputation(state.valueB))
const getTotal = state => getDerivedValueA(state) + getDerivedValueB(state)

const Component = () => {
  const total = useStore(getTotal)
  return <div>{total}</div>;
};

API

memoize

create a memoized function

Parameters

  • fn function (obj: Obj): Result
  • options {size: number?}?

Examples

import memoize from 'proxy-memoize';

const fn = memoize(obj => ({ sum: obj.a + obj.b, diff: obj.a - obj.b }));

Returns function (obj: Obj): Result