サンプル
react 18.2.0: useSyncExternalStore
検証済みサンプル — npm react 18.2.0: useSyncExternalStore. node 22 · linux alpine/x64 · docker で contract を実行し、成功しました: assert React.useSyncExternalStore is exported…
sha256:93852cfa7e6553d0717d354640c446bae9a0e1dac0174dec81a372c6182c0577
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 1
- ビルドした署名鍵
- 1
宣言された環境
linux 24 · ubuntu · glibc 2.39 x64 npm
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-08-27 |
ケース
HOW- ゴール
- verify React.useSyncExternalStore in pkg:npm/react@18.2.0
- パッケージ
- シンボル
-
- React.useSyncExternalStore
- 作成日
- 2026-08-27T10:06:54Z
コントラクト
- assert React.useSyncExternalStore is exported as a function from react
- assert calling useSyncExternalStore outside React component render throws TypeError
- assert server rendering with getServerSnapshot uses server snapshot without subscribing to external store
- assert server rendering without getServerSnapshot throws error requiring getServerSnapshot for server-rendered content
- assert client mounting subscribes to external store and renders initial snapshot
- assert mutating external store triggers synchronous re-render with updated snapshot
- assert unmounting client component cleans up external store subscription
- assert useStoreSelector extracts slices and avoids re-render when selected slice is unchanged
ファイル
- NOTES.md
- PROMPT.md
- csx.json
- package-lock.json
- package.json
- spec.json
- src/index.mjs
- test/contract.mjs
ソース
# React 18 useSyncExternalStore Contract and Behavior
## Prior Search Results
A search for `pkg:npm/react@18.2.0` `React.useSyncExternalStore` returned `NO_SAFE_MATCH`.
## Key Behaviors Proven
1. **Symbol Export**: `React.useSyncExternalStore` is exported as a hook on the `React` object and as a named export from `'react'`.
2. **Hook Execution Context**: Calling `useSyncExternalStore` outside of a React component render phase throws a `TypeError` due to the null dispatcher.
3. **Server Rendering with `getServerSnapshot`**: In server-side rendering (e.g. `renderToString`), `useSyncExternalStore` invokes `getServerSnapshot` and renders the server snapshot without subscribing to the store.
4. **Server Rendering Requirement**: In server-side rendering without `getServerSnapshot`, `useSyncExternalStore` throws `Error: Missing getServerSnapshot, which is required for server-rendered content. Will revert to client rendering.`
5. **Client Subscription Lifecycle**: During client rendering (`createRoot`), mounting increments subscriber count, store mutations trigger re-renders with new snapshots, and unmounting cleanly unsubscribes without memory leaks.
6. **Slice Selection & Stability**: Selectors comparing values via `Object.is` avoid unnecessary re-renders when unselected state properties change.
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: verify React.useSyncExternalStore in pkg:npm/react@18.2.0
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:npm/react@18.2.0
Demonstrate these symbols/APIs:
- React.useSyncExternalStore
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:86edb2563e4515d8b1a2e0161f8e6075a1856516a90bd25ddb893e4371792e7b","contract":["assert React.useSyncExternalStore is exported as a function from react","assert calling useSyncExternalStore outside React component render throws TypeError","assert server rendering with getServerSnapshot uses server snapshot without subscribing to external store","assert server rendering without getServerSnapshot throws error requiring getServerSnapshot for server-rendered content","assert client mounting subscribes to external store and renders initial snapshot","assert mutating external store triggers synchronous re-render with updated snapshot","assert unmounting client component cleans up external store subscription","assert useStoreSelector extracts slices and avoids re-render when selected slice is unchanged"],"goal":"verify React.useSyncExternalStore in pkg:npm/react@18.2.0","kind":"HOW","packages":["pkg:npm/react@18.2.0"],"schemaVersion":1,"symbols":["React.useSyncExternalStore"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/react@18.2.0"],"schemaVersion":1,"subject":"pkg:npm/react@18.2.0","symbols":["React.useSyncExternalStore"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-react-usesyncexternalstore",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-react-usesyncexternalstore",
"version": "1.0.0",
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
},
"peerDependencies": {
"react": "^18.2.0"
}
},
"node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
}
}
}
{
"name": "npm-react-usesyncexternalstore",
"version": "1.0.0",
"private": true,
"type": "module",
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0"
}
}
{
"schemaVersion": 1,
"goal": "verify React.useSyncExternalStore in pkg:npm/react@18.2.0",
"kind": "HOW",
"packages": [
"pkg:npm/react@18.2.0"
],
"symbols": [
"React.useSyncExternalStore"
]
}
import React, { useSyncExternalStore } from 'react';
/**
* Creates an observable external store compatible with React.useSyncExternalStore.
*
* @template T
* @param {T} initialState - Initial state of the store.
* @returns {object} Store object with getState, setState, subscribe, and getSubscriberCount methods.
*/
export function createExternalStore(initialState) {
let state = initialState;
const listeners = new Set();
return {
getState: () => state,
setState: (nextState) => {
const resolved = typeof nextState === 'function' ? nextState(state) : nextState;
if (!Object.is(state, resolved)) {
state = resolved;
listeners.forEach((listener) => {
try {
listener();
} catch {
// Safety against faulty listener callbacks
}
});
}
},
subscribe: (listener) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
},
getSubscriberCount: () => listeners.size,
};
}
/**
* Custom hook to read and subscribe to an external store using React.useSyncExternalStore.
*
* @template T
* @param {object} store - Store created by createExternalStore or conforming to external store contract.
* @param {() => T} [getServerSnapshot] - Optional function returning initial server snapshot.
* @returns {T} Current snapshot of the store.
*/
export function useExternalStore(store, getServerSnapshot) {
return useSyncExternalStore(
store.subscribe,
store.getState,
getServerSnapshot
);
}
/**
* Custom hook to subscribe to a selected slice of an external store using React.useSyncExternalStore.
*
* @template T, R
* @param {object} store - The external store.
* @param {(state: T) => R} selector - Function projecting store state to selected slice.
* @param {() => R} [getServerSnapshot] - Optional function returning initial server snapshot slice.
* @returns {R} Selected slice of the store state.
*/
export function useStoreSelector(store, selector, getServerSnapshot) {
return useSyncExternalStore(
store.subscribe,
() => selector(store.getState()),
getServerSnapshot ? () => selector(getServerSnapshot()) : undefined
);
}
import assert from 'node:assert/strict';
import React, { useSyncExternalStore } from 'react';
import { flushSync } from 'react-dom';
import { renderToString } from 'react-dom/server';
import { createRoot } from 'react-dom/client';
import {
createExternalStore,
useExternalStore,
useStoreSelector,
} from '../src/index.mjs';
// Setup minimal mock DOM environment for offline client testing in Node
globalThis.window = {
HTMLIFrameElement: class HTMLIFrameElement {},
Element: class Element {},
Document: class Document {},
};
function createMockContainer(tagName = 'div') {
return {
nodeType: 1,
tagName: tagName.toUpperCase(),
nodeName: tagName.toUpperCase(),
namespaceURI: 'http://www.w3.org/1999/xhtml',
addEventListener: () => {},
removeEventListener: () => {},
ownerDocument: {
nodeType: 9,
documentElement: {
addEventListener: () => {},
removeEventListener: () => {},
},
addEventListener: () => {},
removeEventListener: () => {},
createElement: (tag) => ({
nodeType: 1,
tagName: tag.toUpperCase(),
nodeName: tag.toUpperCase(),
setAttribute: () => {},
appendChild: () => {},
removeChild: () => {},
addEventListener: () => {},
removeEventListener: () => {},
style: {},
}),
createTextNode: (text) => ({
nodeType: 3,
nodeValue: text,
}),
activeElement: null,
},
appendChild: () => {},
removeChild: () => {},
};
}
// Contract 1: React.useSyncExternalStore is exported as a function on React and as a named export
{
assert.equal(typeof React.useSyncExternalStore, 'function', 'React.useSyncExternalStore is a function');
assert.equal(typeof useSyncExternalStore, 'function', 'useSyncExternalStore named import is a function');
}
// Contract 2: Calling useSyncExternalStore outside of React component execution context throws TypeError
{
assert.throws(
() => useSyncExternalStore(() => () => {}, () => 'snapshot'),
TypeError,
'Calling useSyncExternalStore outside React component throws TypeError because React dispatcher is null'
);
}
// Contract 3: Server rendering uses getServerSnapshot when provided and does not subscribe to the store
{
const store = createExternalStore({ value: 'client-data' });
let getServerSnapshotCalled = false;
function ServerComponent() {
const data = useExternalStore(store, () => {
getServerSnapshotCalled = true;
return { value: 'server-data' };
});
return React.createElement('div', { 'data-testid': 'server-out' }, data.value);
}
const html = renderToString(React.createElement(ServerComponent));
assert.strictEqual(html, '<div data-testid="server-out">server-data</div>', 'Rendered HTML contains server snapshot value');
assert.strictEqual(getServerSnapshotCalled, true, 'getServerSnapshot was invoked during server rendering');
assert.strictEqual(store.getSubscriberCount(), 0, 'External store has no subscribers after server render');
}
// Contract 4: Server rendering throws an error if getServerSnapshot is omitted
{
const store = createExternalStore({ message: 'client-only-state' });
function ServerMissingSnapshotComponent() {
const data = useExternalStore(store);
return React.createElement('p', null, data.message);
}
assert.throws(
() => renderToString(React.createElement(ServerMissingSnapshotComponent)),
/Missing getServerSnapshot, which is required for server-rendered content/,
'Server rendering without getServerSnapshot throws descriptive requirement error'
);
assert.strictEqual(store.getSubscriberCount(), 0, 'No active listeners established during server render failure');
}
// Contract 5: Client component mounts with initial store snapshot and increments subscriber count
{
const store = createExternalStore({ count: 42 });
const observedStates = [];
function ClientComponent() {
const state = useExternalStore(store);
observedStates.push(state);
return React.createElement('span', null, String(state.count));
}
const container = createMockContainer();
const root = createRoot(container);
flushSync(() => {
root.render(React.createElement(ClientComponent));
});
assert.strictEqual(observedStates.length, 1, 'Component rendered initial snapshot');
assert.deepStrictEqual(observedStates[0], { count: 42 }, 'Initial state observed');
assert.strictEqual(store.getSubscriberCount(), 1, 'External store registered 1 subscriber upon mount');
// Contract 6: Store state mutation triggers synchronous re-render and delivers updated snapshot
flushSync(() => {
store.setState({ count: 43 });
});
assert.strictEqual(observedStates.length, 2, 'Component re-rendered upon store update');
assert.deepStrictEqual(observedStates[1], { count: 43 }, 'Updated state observed');
// Contract 7: Unmounting client component unsubscribes from the store
flushSync(() => {
root.unmount();
});
assert.strictEqual(store.getSubscriberCount(), 0, 'Subscriber count drops to 0 after unmount');
// Subsequent store mutations after unmount do not trigger re-render
flushSync(() => {
store.setState({ count: 44 });
});
assert.strictEqual(observedStates.length, 2, 'No re-render occurred after root unmount');
}
// Contract 8: useStoreSelector correctly extracts slices and ignores mutations to unrelated state properties
{
const store = createExternalStore({ name: 'Alpha', score: 100 });
const observedNames = [];
function SlicedComponent() {
const name = useStoreSelector(store, (s) => s.name);
observedNames.push(name);
return React.createElement('div', null, name);
}
const container = createMockContainer();
const root = createRoot(container);
flushSync(() => {
root.render(React.createElement(SlicedComponent));
});
assert.strictEqual(observedNames.length, 1, 'Initial slice observed');
assert.strictEqual(observedNames[0], 'Alpha');
// Update unrelated state slice (score) - name remains 'Alpha'
flushSync(() => {
store.setState((prev) => ({ ...prev, score: 200 }));
});
// Because selector returned identical primitive ('Alpha'), React skips re-render
assert.strictEqual(observedNames.length, 1, 'Selector avoided re-render when selected slice did not change');
// Update relevant slice (name) - triggers re-render
flushSync(() => {
store.setState((prev) => ({ ...prev, name: 'Beta' }));
});
assert.strictEqual(observedNames.length, 2, 'Selector triggered re-render when selected slice changed');
assert.strictEqual(observedNames[1], 'Beta');
flushSync(() => {
root.unmount();
});
assert.strictEqual(store.getSubscriberCount(), 0, 'Sliced component cleaned up subscription on unmount');
}
console.log('All React.useSyncExternalStore contract assertions passed successfully!');
オリジンシーダー
匿名