-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathContextChangeDemo.tsx
153 lines (138 loc) · 3.58 KB
/
ContextChangeDemo.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import {
EvaluationContext,
InMemoryProvider,
OpenFeature,
OpenFeatureProvider,
useBooleanFlagDetails,
useFlag,
useContextMutator,
} from "@openfeature/react-sdk";
import { Suspense } from "react";
import { useSearchParams } from "react-router-dom";
import {
CONTEXT_CHANGE_DEMO_EXPLANATION,
CONTEXT_CHANGE_DEMO_NAME,
} from "../constants";
import hourglass from "../hourglass.svg";
import logo from "../logo.svg";
import "./Demo.css";
const PROVIDER_NAME = CONTEXT_CHANGE_DEMO_NAME;
/**
* A component associated with a provider that becomes ready after a few seconds.
* It demonstrates the "Suspense" support of the React SDK.
*/
function ContextChangeDemo() {
const [searchParams] = useSearchParams();
const goFastName = "go-fast";
const flagConfig = {
[goFastName]: {
disabled: false,
variants: {
on: true,
off: false,
},
defaultVariant: "on",
contextEvaluator: (context: EvaluationContext) => {
if (context.silly) {
return "on";
}
return "off";
},
},
};
const provider = new DelayedContextUpdateProvider(
flagConfig,
Number.parseInt(searchParams.get("delay") || "0")
);
// Set our provider, give it a name matching the scope of our OpenFeatureProvider below
OpenFeature.setProvider(PROVIDER_NAME, provider);
return (
// This page is scoped to the "suspense" provider.
<OpenFeatureProvider domain={PROVIDER_NAME} suspend={true}>
<Content />
</OpenFeatureProvider>
);
}
function Content() {
return (
<div className="Demo">
<header className="Demo-header">
<p className="Demo-description small-text bounded-text">{CONTEXT_CHANGE_DEMO_EXPLANATION}</p>
<ContextChangeButton />
<Suspense fallback={<Fallback />}>
<Spinner />
</Suspense>
</header>
</div>
);
}
function ContextChangeButton() {
const {
mutateContext,
} = useContextMutator();
return (
<span>
<span>Click </span>
<button
onClick={() => {
mutateContext(PROVIDER_NAME, {
silly: !OpenFeature.getContext(PROVIDER_NAME).silly,
});
}}
>
here
</button>
<span> to modify the evaluation context</span>
</span>
);
}
function Spinner() {
// evaluate flag with react-query style API
const { value: goFast } = useFlag("go-fast", false);
return (
<>
<img
src={logo}
className="Demo-logo Demo-spin"
style={{
padding: 20,
animation: goFast ? "spin infinite 1s linear" : "",
}}
alt="logo"
/>
{goFast ? (
<p>Welcome to this silly React app!</p>
) : (
<p>Welcome to this React app.</p>
)}
</>
);
}
/**
* A provider who's onContextChange is delayed for 'delay' seconds to demonstrate the React SDK's Suspense features.
*/
class DelayedContextUpdateProvider extends InMemoryProvider {
constructor(
flagConfiguration: ConstructorParameters<typeof InMemoryProvider>[0],
private delay: number
) {
super(flagConfiguration);
}
// override to artificially delay our context change for demo purposes
async onContextChange(
oldContext: EvaluationContext,
newContext: EvaluationContext
): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, this.delay)).then(() => {
});
}
}
function Fallback() {
return (
<>
<img src={hourglass} className="Demo-logo Fallback-img" alt="hourglass" />
<p>Waiting for provider context-update...</p>
</>
);
}
export default ContextChangeDemo;