@ninetailed/experience.js-react 7.12.1 → 7.13.0-beta.1

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.
Files changed (3) hide show
  1. package/index.cjs.js +33 -24
  2. package/index.esm.js +35 -24
  3. package/package.json +4 -4
package/index.cjs.js CHANGED
@@ -100,7 +100,6 @@ function __rest(s, e) {
100
100
  }
101
101
 
102
102
  function formatProfileForHook(profile) {
103
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
104
103
  const profileStateWithoutExperiences = __rest(profile, ["experiences"]);
105
104
  return Object.assign(Object.assign({}, profileStateWithoutExperiences), {
106
105
  loading: profile.status === 'loading'
@@ -162,29 +161,36 @@ const usePersonalize = (baseline, variants, options = {
162
161
  function useFlag(flagKey, defaultValue) {
163
162
  const ninetailed = useNinetailed();
164
163
  const lastProcessedState = React.useRef(null);
164
+ const defaultValueRef = React.useRef(defaultValue);
165
+ const flagKeyRef = React.useRef(flagKey);
165
166
  const [result, setResult] = React.useState({
166
167
  value: defaultValue,
167
168
  status: 'loading',
168
169
  error: null
169
170
  });
171
+ // Effect 1: Track changes to `flagKey` or `defaultValue`
172
+ React.useEffect(() => {
173
+ if (!radash.isEqual(defaultValueRef.current, defaultValue) || flagKeyRef.current !== flagKey) {
174
+ defaultValueRef.current = defaultValue;
175
+ flagKeyRef.current = flagKey;
176
+ setResult({
177
+ value: defaultValue,
178
+ status: 'loading',
179
+ error: null
180
+ });
181
+ lastProcessedState.current = null;
182
+ }
183
+ }, [flagKey, defaultValue]);
184
+ // Effect 2: Handle Ninetailed changes
170
185
  React.useEffect(() => {
171
- // Reset state when dependencies change
172
- setResult({
173
- value: defaultValue,
174
- status: 'loading',
175
- error: null
176
- });
177
- lastProcessedState.current = null;
178
186
  const unsubscribe = ninetailed.onChangesChange(changesState => {
179
187
  if (lastProcessedState.current && radash.isEqual(lastProcessedState.current, changesState)) {
180
- experience_jsShared.logger.debug('Change State Did Not Change', changesState);
181
188
  return;
182
189
  }
183
190
  lastProcessedState.current = changesState;
184
191
  if (changesState.status === 'loading') {
185
- // Don't use a function updater here to avoid type issues
186
192
  setResult({
187
- value: defaultValue,
193
+ value: defaultValueRef.current,
188
194
  status: 'loading',
189
195
  error: null
190
196
  });
@@ -192,40 +198,37 @@ function useFlag(flagKey, defaultValue) {
192
198
  }
193
199
  if (changesState.status === 'error') {
194
200
  setResult({
195
- value: defaultValue,
201
+ value: defaultValueRef.current,
196
202
  status: 'error',
197
203
  error: changesState.error
198
204
  });
199
205
  return;
200
206
  }
201
207
  try {
202
- // Find the change with our flag key
203
- const change = changesState.changes.find(change => change.key === flagKey);
208
+ const change = changesState.changes.find(change => change.key === flagKeyRef.current);
204
209
  if (change && change.type === experience_jsShared.ChangeTypes.Variable) {
205
- const flagValue = change.value;
206
210
  setResult({
207
- value: flagValue,
211
+ value: change.value,
208
212
  status: 'success',
209
213
  error: null
210
214
  });
211
215
  } else {
212
- // Flag not found or wrong type, use default
213
216
  setResult({
214
- value: defaultValue,
217
+ value: defaultValueRef.current,
215
218
  status: 'success',
216
219
  error: null
217
220
  });
218
221
  }
219
222
  } catch (error) {
220
223
  setResult({
221
- value: defaultValue,
224
+ value: defaultValueRef.current,
222
225
  status: 'error',
223
226
  error: error instanceof Error ? error : new Error(String(error))
224
227
  });
225
228
  }
226
229
  });
227
230
  return unsubscribe;
228
- }, [ninetailed, flagKey, defaultValue]);
231
+ }, [ninetailed]);
229
232
  return result;
230
233
  }
231
234
 
@@ -531,9 +534,7 @@ const Experience = _a => {
531
534
  const componentElement = componentRef.current;
532
535
  if (componentElement && !(componentElement instanceof Element)) {
533
536
  const isObject = typeof componentElement === 'object' && componentElement !== null;
534
- const constructorName = isObject ?
535
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
536
- componentElement.constructor.name : '';
537
+ const constructorName = isObject ? componentElement.constructor.name : '';
537
538
  const isConstructorNameNotObject = constructorName && constructorName !== 'Object';
538
539
  logger.warn(`The component ref being in Experience is an invalid element. Expected an Element but got ${typeof componentElement}${isConstructorNameNotObject ? ` of type ${constructorName}` : ''}. This component won't be observed.`);
539
540
  return () => {
@@ -644,7 +645,15 @@ const ESRLoadingComponent = _a => {
644
645
  }
645
646
  }));
646
647
  }
647
- const component = experience.components.find(component => component.baseline.id === baseline.id);
648
+ const component = experience.components.find(component => {
649
+ if (!('id' in component.baseline)) {
650
+ return false;
651
+ }
652
+ if (!('id' in baseline)) {
653
+ return component.baseline.id === undefined;
654
+ }
655
+ return component.baseline.id === baseline.id;
656
+ });
648
657
  if (!component) {
649
658
  return jsxRuntime.jsx(Component, Object.assign({}, passthroughProps, baseline, {
650
659
  ninetailed: {
package/index.esm.js CHANGED
@@ -78,7 +78,6 @@ function _objectWithoutPropertiesLoose(source, excluded) {
78
78
 
79
79
  const _excluded$3 = ["experiences"];
80
80
  function formatProfileForHook(profile) {
81
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
81
  const profileStateWithoutExperiences = _objectWithoutPropertiesLoose(profile, _excluded$3);
83
82
  return Object.assign({}, profileStateWithoutExperiences, {
84
83
  loading: profile.status === 'loading'
@@ -143,29 +142,38 @@ const usePersonalize = (baseline, variants, options = {
143
142
  function useFlag(flagKey, defaultValue) {
144
143
  const ninetailed = useNinetailed();
145
144
  const lastProcessedState = useRef(null);
145
+ const defaultValueRef = useRef(defaultValue);
146
+ const flagKeyRef = useRef(flagKey);
146
147
  const [result, setResult] = useState({
147
148
  value: defaultValue,
148
149
  status: 'loading',
149
150
  error: null
150
151
  });
152
+
153
+ // Effect 1: Track changes to `flagKey` or `defaultValue`
154
+ useEffect(() => {
155
+ if (!isEqual(defaultValueRef.current, defaultValue) || flagKeyRef.current !== flagKey) {
156
+ defaultValueRef.current = defaultValue;
157
+ flagKeyRef.current = flagKey;
158
+ setResult({
159
+ value: defaultValue,
160
+ status: 'loading',
161
+ error: null
162
+ });
163
+ lastProcessedState.current = null;
164
+ }
165
+ }, [flagKey, defaultValue]);
166
+
167
+ // Effect 2: Handle Ninetailed changes
151
168
  useEffect(() => {
152
- // Reset state when dependencies change
153
- setResult({
154
- value: defaultValue,
155
- status: 'loading',
156
- error: null
157
- });
158
- lastProcessedState.current = null;
159
169
  const unsubscribe = ninetailed.onChangesChange(changesState => {
160
170
  if (lastProcessedState.current && isEqual(lastProcessedState.current, changesState)) {
161
- logger.debug('Change State Did Not Change', changesState);
162
171
  return;
163
172
  }
164
173
  lastProcessedState.current = changesState;
165
174
  if (changesState.status === 'loading') {
166
- // Don't use a function updater here to avoid type issues
167
175
  setResult({
168
- value: defaultValue,
176
+ value: defaultValueRef.current,
169
177
  status: 'loading',
170
178
  error: null
171
179
  });
@@ -173,40 +181,37 @@ function useFlag(flagKey, defaultValue) {
173
181
  }
174
182
  if (changesState.status === 'error') {
175
183
  setResult({
176
- value: defaultValue,
184
+ value: defaultValueRef.current,
177
185
  status: 'error',
178
186
  error: changesState.error
179
187
  });
180
188
  return;
181
189
  }
182
190
  try {
183
- // Find the change with our flag key
184
- const change = changesState.changes.find(change => change.key === flagKey);
191
+ const change = changesState.changes.find(change => change.key === flagKeyRef.current);
185
192
  if (change && change.type === ChangeTypes.Variable) {
186
- const flagValue = change.value;
187
193
  setResult({
188
- value: flagValue,
194
+ value: change.value,
189
195
  status: 'success',
190
196
  error: null
191
197
  });
192
198
  } else {
193
- // Flag not found or wrong type, use default
194
199
  setResult({
195
- value: defaultValue,
200
+ value: defaultValueRef.current,
196
201
  status: 'success',
197
202
  error: null
198
203
  });
199
204
  }
200
205
  } catch (error) {
201
206
  setResult({
202
- value: defaultValue,
207
+ value: defaultValueRef.current,
203
208
  status: 'error',
204
209
  error: error instanceof Error ? error : new Error(String(error))
205
210
  });
206
211
  }
207
212
  });
208
213
  return unsubscribe;
209
- }, [ninetailed, flagKey, defaultValue]);
214
+ }, [ninetailed]);
210
215
  return result;
211
216
  }
212
217
 
@@ -515,9 +520,7 @@ const Experience = _ref2 => {
515
520
  const componentElement = componentRef.current;
516
521
  if (componentElement && !(componentElement instanceof Element)) {
517
522
  const isObject = typeof componentElement === 'object' && componentElement !== null;
518
- const constructorName = isObject ?
519
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
520
- componentElement.constructor.name : '';
523
+ const constructorName = isObject ? componentElement.constructor.name : '';
521
524
  const isConstructorNameNotObject = constructorName && constructorName !== 'Object';
522
525
  logger.warn(`The component ref being in Experience is an invalid element. Expected an Element but got ${typeof componentElement}${isConstructorNameNotObject ? ` of type ${constructorName}` : ''}. This component won't be observed.`);
523
526
  return () => {
@@ -628,7 +631,15 @@ const ESRLoadingComponent = _ref => {
628
631
  }
629
632
  }));
630
633
  }
631
- const component = experience.components.find(component => component.baseline.id === baseline.id);
634
+ const component = experience.components.find(component => {
635
+ if (!('id' in component.baseline)) {
636
+ return false;
637
+ }
638
+ if (!('id' in baseline)) {
639
+ return component.baseline.id === undefined;
640
+ }
641
+ return component.baseline.id === baseline.id;
642
+ });
632
643
  if (!component) {
633
644
  return /*#__PURE__*/jsx(Component, Object.assign({}, passthroughProps, baseline, {
634
645
  ninetailed: {
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js-react",
3
- "version": "7.12.1",
3
+ "version": "7.13.0-beta.1",
4
4
  "description": "Ninetailed SDK for React",
5
5
  "dependencies": {
6
- "@ninetailed/experience.js": "7.12.1",
7
- "@ninetailed/experience.js-shared": "7.12.1",
8
- "@ninetailed/experience.js-plugin-analytics": "7.12.1",
6
+ "@ninetailed/experience.js": "7.13.0-beta.1",
7
+ "@ninetailed/experience.js-shared": "7.13.0-beta.1",
8
+ "@ninetailed/experience.js-plugin-analytics": "7.13.0-beta.1",
9
9
  "radash": "10.9.0",
10
10
  "react-is": "18.2.0"
11
11
  },