Skip to content

Added createRcMemo primitive#853

Merged
davedbase merged 5 commits into
solidjs-community:mainfrom
clinuxrulz:create-rc-memo
Jun 3, 2026
Merged

Added createRcMemo primitive#853
davedbase merged 5 commits into
solidjs-community:mainfrom
clinuxrulz:create-rc-memo

Conversation

@clinuxrulz

@clinuxrulz clinuxrulz commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

createRcMemo is similar to createLazyMemo except its lifetime is bounded by the existence of listeners. (the listeners are reference counted.)

  • Initially when there are no listeners, the internal memo is not created.
  • When it goes from 0 listeners, to some listeners the internal memo is constructed.
  • When it goes from some listeners, to zero listeners the internal memo is deconstructed.
  • The internal memo can be reconstructed again after it has been deconstructed.
  • For the context being passed along, it will carry the context of the owner of which createRcMemo was called inside.

Summary by CodeRabbit

  • New Features

    • Introduced createRcMemo - a reference-counted memo primitive that automatically manages computational resources by executing only when active listeners exist, and cleaning up when all listeners are removed.
  • Documentation

    • Added comprehensive createRcMemo documentation with usage examples and behavior details.

@changeset-bot

changeset-bot Bot commented Apr 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2c87347

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solid-primitives/memo Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@atk atk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no documentation in the README.md, and this also needs a changeset file (please run npx changeset and add a minor version). Lastly, add createRcMemo to package.json in the primitive.list array.

/**
* Reference counted `createMemo`. The memo calculation will only run when there is at least one listener.
*
* Once the number of listeners drops to zero, the internal memo will be disposed after a microtask.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add that the prev argument to the memo will be based on the previous value after being without listeners and being re-initialized, even if intermediate computations would have led to a different value. Maybe consider providing an additional stale argument (or similar mechanism) to the handler.

Comment thread packages/memo/src/index.ts
Comment thread packages/memo/src/index.ts Outdated
let existing2 = existing!;
onCleanup(() => {
existing2.refCount--;
if (existing2.refCount == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use type-safe comparisons unless you consciously want to match other types, e.g. in line 485.

@clinuxrulz

clinuxrulz commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

@atk I believe I have address your requested changes.
Except for npx changeset, that command did not make any file changes on my machine, so I am a little confused.

Maybe you can try the npx changeset command on your end?

Regarding prev to clear things up. When an internal memo is disposed later on, and reconstructed again later later on, the prev value will not reset to the initial value provided to createRcMemo, it will instead carry on the last-seen prev value. If it seems unclear in the documentation still, I can try and clear it up.

I've used that createRcMemo pattern a lot in production code at work. I believe it's a handy one to have available.

@clinuxrulz

Copy link
Copy Markdown
Contributor Author

@atk changeset added. Apologies for before, I did not understand how the npx changeset worked.

@davedbase

Copy link
Copy Markdown
Member

@clinuxrulz I'm going to merge this in but our 2.0 implementation wont have the changes. I'll try to port it with a new PR later this evening.

@davedbase davedbase merged commit a291aa0 into solidjs-community:main Jun 3, 2026
1 check was pending
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 38adb1f9-0b2f-4139-bbe4-c6ee46427733

📥 Commits

Reviewing files that changed from the base of the PR and between ea386c4 and 2c87347.

📒 Files selected for processing (5)
  • .changeset/lovely-bags-sin.md
  • packages/memo/README.md
  • packages/memo/package.json
  • packages/memo/src/index.ts
  • packages/memo/test/rcMemo.test.ts

📝 Walkthrough

Walkthrough

A new createRcMemo primitive is introduced to the @solid-primitives/memo package. It provides reference-counted memoization where the internal memo is lazily created only when there are active listeners and disposed via microtask scheduling when listener count reaches zero. The feature includes full test coverage and documentation.

Changes

createRcMemo Reference-Counted Primitive

Layer / File(s) Summary
Core implementation with import and reference counting
packages/memo/src/index.ts
The createRcMemo function is implemented with three overloads supporting optional initial values. Uses getListener to detect active listeners and manages reference counting via onCleanup. Lazily creates an internal memo via createRoot and schedules disposal after zero listeners using queueMicrotask. On the server, caches a single computed result on first access.
Test suite for listener lifecycle and state persistence
packages/memo/test/rcMemo.test.ts
Vitest suite validates listener-dependent memo creation, deferred disposal via microtask, prevention of premature disposal when listeners are added within the same microtask (memo reuse), multiple concurrent listener handling, SolidJS context propagation into the inner memo, and prev argument persistence across memo life cycles.
Documentation, README, and release metadata
packages/memo/README.md, packages/memo/package.json, .changeset/lovely-bags-sin.md
README feature list and detailed section document reference-counted behavior, listener-driven lifecycle, and server-side caching. Package metadata registers the primitive in primitive.list. Changesets entry documents the minor release.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • atk

Poem

🐰 A memo now counts, with ears held high,
It lives while listened, then says goodbye,
Microtasks defer the final farewell,
While context flows through its shell,
Reference dance—listener by listener—we thrive! ✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants