@toggld/react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +16 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ A component re-renders only when **its** flag's result changes.
|
|
|
45
45
|
## Server-side rendering
|
|
46
46
|
|
|
47
47
|
Create the client in the root component with `useState(() => new ToggldClient({
|
|
48
|
-
…, bootstrap }))`, where `bootstrap` is `@toggld/
|
|
48
|
+
…, bootstrap }))`, where `bootstrap` is `@toggld/js`'s `evaluateAll(context)`
|
|
49
49
|
from the server. Server output and hydration match, and the browser sends no
|
|
50
50
|
first request.
|
|
51
51
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, createElement, useContext, useRef, useSyncExternalStore } from "react";
|
|
1
|
+
import { createContext, createElement, useContext, useEffect, useRef, useSyncExternalStore } from "react";
|
|
2
2
|
import { ToggldClient } from "@toggld/browser";
|
|
3
3
|
// src/index.ts
|
|
4
4
|
/**
|
|
@@ -30,6 +30,9 @@ import { ToggldClient } from "@toggld/browser";
|
|
|
30
30
|
* that did not change by identity, and the hooks compare by identity. Built on
|
|
31
31
|
* `useSyncExternalStore`, so server rendering and hydration work when the
|
|
32
32
|
* client is created with a `bootstrap`.
|
|
33
|
+
*
|
|
34
|
+
* For Analytics, a hook counts one read when its component mounts with a
|
|
35
|
+
* value, and one more each time its result changes, not one per render.
|
|
33
36
|
*/
|
|
34
37
|
const ClientContext = createContext(null);
|
|
35
38
|
ClientContext.displayName = "ToggldClient";
|
|
@@ -57,6 +60,8 @@ function useToggldStatus() {
|
|
|
57
60
|
const getStatus = () => client.getSnapshot().status;
|
|
58
61
|
return useSyncExternalStore(client.subscribe, getStatus, getStatus);
|
|
59
62
|
}
|
|
63
|
+
const INTERNAL = Symbol.for("toggld.browser.internal");
|
|
64
|
+
const internalOf = (client) => client[INTERNAL];
|
|
60
65
|
/** Evaluate with the getter that matches the default value's type. */
|
|
61
66
|
const evaluateTyped = (client, key, defaultValue) => {
|
|
62
67
|
switch (typeof defaultValue) {
|
|
@@ -79,14 +84,22 @@ const sameMetadata = (a, b) => {
|
|
|
79
84
|
const sameDetails = (a, b) => a === b || a.flagKey === b.flagKey && Object.is(a.value, b.value) && a.variant === b.variant && a.reason === b.reason && a.errorCode === b.errorCode && a.errorMessage === b.errorMessage && sameMetadata(a.flagMetadata, b.flagMetadata);
|
|
80
85
|
function useFlagDetails(key, defaultValue) {
|
|
81
86
|
const client = useToggldClient();
|
|
87
|
+
const internal = internalOf(client);
|
|
82
88
|
const cache = useRef(null);
|
|
89
|
+
const counted = useRef(null);
|
|
83
90
|
const get = () => {
|
|
84
|
-
const details = evaluateTyped(client, key, defaultValue);
|
|
91
|
+
const details = internal?.peek(key, defaultValue) ?? evaluateTyped(client, key, defaultValue);
|
|
85
92
|
if (cache.current !== null && sameDetails(cache.current, details)) return cache.current;
|
|
86
93
|
cache.current = details;
|
|
87
94
|
return details;
|
|
88
95
|
};
|
|
89
|
-
|
|
96
|
+
const details = useSyncExternalStore(client.subscribe, get, get);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (counted.current === details) return;
|
|
99
|
+
counted.current = details;
|
|
100
|
+
internal?.record(details);
|
|
101
|
+
}, [details, internal]);
|
|
102
|
+
return details;
|
|
90
103
|
}
|
|
91
104
|
function useFlag(key, defaultValue) {
|
|
92
105
|
return useFlagDetails(key, defaultValue).value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toggld/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React bindings for the Toggld browser SDK — a provider and hooks that re-render only when a flag's value changes. Server-rendering friendly.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://toggld.io",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|
|
39
|
-
"@toggld/browser": "^0.
|
|
39
|
+
"@toggld/browser": "^0.2.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/react": "^19.3.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"react-dom": "^19.3.1",
|
|
47
47
|
"tsdown": "^0.23.2",
|
|
48
48
|
"typescript": "6.0.3",
|
|
49
|
-
"@toggld/browser": "0.
|
|
49
|
+
"@toggld/browser": "0.2.0"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"build": "tsdown",
|