mrkeyoor.com_
Sat 08 Aug 22:54 UTC
npmWeb Frontendupdated 08 Aug 2026

use-memo-one

use-memo-one is a tiny pair of React hooks that mirrors useMemo and useCallback while promising to keep the last cached reference until its component is garbage-collected. The built-in React hooks are performance hints whose caches React may discard; useMemoOne and useCallbackOne make reference stability part of their contract as long as every dependency remains strictly equal. That narrow guarantee can help code where object or callback identity is observable, but it uses more memory and does not make missing dependencies safe.

Verdict

A focused compatibility tool for React 16.8 through 18 when stable cache identity is genuinely semantic. Most new code should use React's built-ins, and React 19 projects should not add a package whose declared peer support and maintenance stopped at React 18.

API stability4/5The public surface has stayed at two hooks plus two aliases, and the README deliberately matches React's useMemo and useCallback signatures. Source and bundled TypeScript declarations agree on the dependency-list contract. The lost point is compatibility rather than churn: the published peer range stops at React 18, so the unchanged API has not been certified for React 19.
Docs3/5The README clearly explains the stable-cache promise, extra memory cost, named exports, alias collision, linting setup, and two basic examples. It does not document React 19 compatibility, Strict Mode behavior, server rendering, or common stale-closure mistakes, and its API section sends readers to an older React hooks reference instead of maintaining a full reference locally.
Maintenance1/5npm shows version 1.1.3 was published on August 31, 2022, GitHub reports the last repository push on December 8, 2022, and the latest commits were release and CI work around adding React 18 peer support. The repository is not archived, but four years without a release or React 19 peer update is strong evidence that consumers should expect to carry compatibility risk themselves.
Ecosystem3/5The package recorded 3,323,475 npm downloads for the measured week and has no runtime dependencies, so it remains widely present and cheap to consume transitively. Its integration story is deliberately narrow: React is the only peer, eslint-plugin-react-hooks works best through aliased imports, and the published peer range excludes the current React 19 line.

Use it if

  • You need a memoized object or callback to retain the same reference while its dependency list is unchanged
  • A third-party component or subscription treats reference identity as behavior, not just a rendering optimization
  • You maintain a React 16.8 through 18 application and want an API that can replace useMemo or useCallback with minimal code changes
  • You want zero runtime dependencies beyond the required React peer
Skip it if

Setup reality

Installation is one npm command and the package has no runtime dependencies, but peer compatibility is the first surprise. Version 1.1.3 accepts react ^16.8.0, ^17.0.0, or ^18.0.0; React 19 is outside that declared range, so npm may warn and stricter installers may stop. The package ships CommonJS and ESM builds plus its own index.d.ts, so React 16.8 through 18 projects need no compiler plugin or type package. There are four named exports: useMemoOne, useCallbackOne, and drop-in aliases named useMemo and useCallback. The aliases make eslint-plugin-react-hooks recognize dependency arrays, but they collide if the same file also imports those names from react. The dependency check is shallow and positional, using strict equality for each item. An inline object, array, or function in the dependency list changes on every render unless stabilized first. Omitting the dependency list does not mean cache forever; the repository tests confirm that no list recomputes on every render. An empty list retains the first value, which also means a callback can capture initial props forever. Factories still run during rendering and must be pure, especially under React development checks. Finally, this guarantee costs memory: the README says the last cache is retained until the component can be garbage-collected, rather than being releasable by React.

Patterns

Keep a derived object reference stablememoize-derived-object

import { useMemoOne } from 'use-memo-one';

function Profile({ name, role }) {
  const summary = useMemoOne(() => ({ name, role }), [name, role]);
  return <ProfileCard summary={summary} />;
}

The same object is returned while both dependencies are strictly equal; a change to either creates a new object.

Keep a callback stable until its input changesmemoize-callback

import { useCallbackOne } from 'use-memo-one';

function SaveButton({ documentId, save }) {
  const onSave = useCallbackOne(() => save(documentId), [save, documentId]);
  return <button onClick={onSave}>Save</button>;
}

List every captured value. Stable identity does not prevent a stale closure when a dependency is omitted.

Use aliases recognized by hooks lintinguse-lint-friendly-aliases

import { useMemo, useCallback } from 'use-memo-one';

const options = useMemo(() => ({ roomId }), [roomId]);
const connect = useCallback(() => openRoom(roomId), [roomId]);

Do not also import useMemo or useCallback from react in this file; the README warns that the names collide.

Stabilize a context provider valuememoize-context-value

import { useMemoOne } from 'use-memo-one';

function SessionProvider({ user, signOut, children }) {
  const value = useMemoOne(() => ({ user, signOut }), [user, signOut]);
  return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;
}

This only prevents identity changes when user and signOut are stable; it does not stop consumers rendering when either really changes.

Pass a stable prop to a memoized childsupport-memoized-child

import { memo } from 'react';
import { useMemoOne } from 'use-memo-one';

const Chart = memo(({ config }) => <ChartCanvas config={config} />);

function Dashboard({ theme, limit }) {
  const config = useMemoOne(() => ({ theme, limit }), [theme, limit]);
  return <Chart config={config} />;
}

Memoizing the prop helps only if Chart is memoized or otherwise observes reference identity.

Avoid reconnecting an effect for an equivalent options objectstabilize-effect-dependency

import { useEffect } from 'react';
import { useMemoOne } from 'use-memo-one';

function Room({ roomId, serverUrl }) {
  const options = useMemoOne(() => ({ roomId, serverUrl }), [roomId, serverUrl]);

  useEffect(() => {
    const connection = connect(options);
    return () => connection.close();
  }, [options]);
}

Prefer creating simple effect-only objects inside the effect when possible; this pattern is for code that also needs the stable object elsewhere.

Create one value for a mounted componentcache-for-component-lifetime

import { useMemoOne } from 'use-memo-one';

function Editor() {
  const model = useMemoOne(() => createEditorModel(), []);
  return <EditorView model={model} />;
}

An empty dependency list retains the initial result while mounted. The factory must be pure because it runs during rendering and development checks may invoke rendering more than once.

Understand an omitted dependency listrecompute-every-render

import { useMemoOne } from 'use-memo-one';

function Clock() {
  const snapshot = useMemoOne(() => ({ renderedAt: Date.now() }));
  return <time>{snapshot.renderedAt}</time>;
}

Repository tests confirm that omitting the second argument does not memoize across renders. Pass [] only when retaining the first result is intentional.

Depend on primitives instead of a new objectavoid-unstable-dependencies

// Bad: filter is new on every render
const filter = { status, owner };
const rows = useMemoOne(() => selectRows(data, filter), [data, filter]);

// Better: build it inside the factory
const rows = useMemoOne(
  () => selectRows(data, { status, owner }),
  [data, status, owner],
);

The source uses strict equality for each dependency. It does not perform deep or structural comparison.

Preserve callback parameter types in TypeScripttype-callback-parameters

import { useCallbackOne } from 'use-memo-one';

function Search({ runSearch }: { runSearch: (query: string) => void }) {
  const submit = useCallbackOne((query: string) => {
    runSearch(query.trim());
  }, [runSearch]);

  return <SearchBox onSubmit={submit} />;
}

The bundled declaration keeps the callback's function type, but React 19 remains outside the package's declared peer range.

Alternatives

PackageRegistryPick it when
reactnpmUse built-in useMemo and useCallback when cache identity is only a performance optimization or when the app is on React 19
memoize-onenpmMemoize the latest call of a regular function outside React's hook lifecycle
use-callback-refnpmKeep a callable reference stable while updating the function it invokes, which is a better fit for latest-value event callbacks