@ninetailed/experience.js-react 7.11.0-beta.1 → 7.12.0-beta.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/index.cjs.js +116 -21
- package/index.esm.js +119 -23
- package/package.json +4 -4
- package/src/lib/index.d.ts +1 -0
- package/src/lib/useFlag.d.ts +22 -0
- package/src/lib/useProfile.d.ts +15 -51
package/index.cjs.js
CHANGED
|
@@ -99,32 +99,49 @@ function __rest(s, e) {
|
|
|
99
99
|
return t;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
function formatProfileForHook(profile) {
|
|
103
|
+
const profileStateWithoutExperiences = __rest(profile, ["experiences"]);
|
|
104
|
+
return Object.assign(Object.assign({}, profileStateWithoutExperiences), {
|
|
105
|
+
loading: profile.status === 'loading'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Custom hook that provides access to the Ninetailed profile state
|
|
110
|
+
* with the 'experiences' property removed to prevent unnecessary re-renders.
|
|
111
|
+
*
|
|
112
|
+
* This hook handles profile state changes efficiently by:
|
|
113
|
+
* 1. Only updating state when actual changes occur
|
|
114
|
+
* 2. Removing the large 'experiences' object from the state
|
|
115
|
+
* 3. Properly cleaning up subscriptions when components unmount
|
|
116
|
+
*
|
|
117
|
+
* @returns The profile state without the 'experiences' property
|
|
118
|
+
*/
|
|
102
119
|
const useProfile = () => {
|
|
103
120
|
const ninetailed = useNinetailed();
|
|
104
|
-
const [
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* This effect compares the old and new profile state before updating it.
|
|
108
|
-
* We use a ref to avoid an infinite loop which can happen when an empty profile state was updated with no changes.
|
|
109
|
-
* This behaviour occurred as the validation handling on the error property was not set properly in the "CreateProfile" and "UpdateProfile" endpoint types.
|
|
110
|
-
* Furthermore, it was also observed, that it "only" occurred when the preview plugin was used in parallel.
|
|
111
|
-
*/
|
|
121
|
+
const [strippedProfileState, setStrippedProfileState] = React.useState(formatProfileForHook(ninetailed.profileState));
|
|
122
|
+
// Reference to track the previous profile state for comparison
|
|
123
|
+
const profileStateRef = React.useRef(ninetailed.profileState);
|
|
112
124
|
React.useEffect(() => {
|
|
113
|
-
ninetailed.onProfileChange(
|
|
114
|
-
if
|
|
115
|
-
|
|
125
|
+
const unsubscribe = ninetailed.onProfileChange(changedProfileState => {
|
|
126
|
+
// Skip update if the profile hasn't actually changed
|
|
127
|
+
// Here we compare the entire profile including experiences and changes
|
|
128
|
+
if (radash.isEqual(changedProfileState, profileStateRef.current)) {
|
|
129
|
+
experience_jsShared.logger.debug('Profile State Did Not Change', changedProfileState);
|
|
116
130
|
return;
|
|
117
|
-
} else {
|
|
118
|
-
setProfileState(profileState);
|
|
119
|
-
profileStateRef.current = profileState;
|
|
120
|
-
experience_jsShared.logger.debug('Profile State Changed', profileState);
|
|
121
131
|
}
|
|
132
|
+
profileStateRef.current = changedProfileState;
|
|
133
|
+
experience_jsShared.logger.debug('Profile State Changed', changedProfileState);
|
|
134
|
+
setStrippedProfileState(formatProfileForHook(changedProfileState));
|
|
122
135
|
});
|
|
136
|
+
// Clean up subscription when component unmounts
|
|
137
|
+
return () => {
|
|
138
|
+
if (typeof unsubscribe === 'function') {
|
|
139
|
+
unsubscribe();
|
|
140
|
+
experience_jsShared.logger.debug('Unsubscribed from profile state changes');
|
|
141
|
+
}
|
|
142
|
+
};
|
|
123
143
|
}, []);
|
|
124
|
-
|
|
125
|
-
return Object.assign(Object.assign({}, profileStateWithoutExperiences), {
|
|
126
|
-
loading: profileState.status === 'loading'
|
|
127
|
-
});
|
|
144
|
+
return strippedProfileState;
|
|
128
145
|
};
|
|
129
146
|
|
|
130
147
|
const usePersonalize = (baseline, variants, options = {
|
|
@@ -134,6 +151,83 @@ const usePersonalize = (baseline, variants, options = {
|
|
|
134
151
|
return experience_js.selectVariant(baseline, variants, profile, options);
|
|
135
152
|
};
|
|
136
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Custom hook to retrieve a specific feature flag from Ninetailed changes.
|
|
156
|
+
*
|
|
157
|
+
* @param flagKey - The key of the feature flag to retrieve
|
|
158
|
+
* @param defaultValue - The default value to use if the flag is not found
|
|
159
|
+
* @returns An object containing the flag value and status information
|
|
160
|
+
*/
|
|
161
|
+
function useFlag(flagKey, defaultValue) {
|
|
162
|
+
const ninetailed = useNinetailed();
|
|
163
|
+
const lastProcessedState = React.useRef(null);
|
|
164
|
+
const [result, setResult] = React.useState({
|
|
165
|
+
value: defaultValue,
|
|
166
|
+
status: 'loading',
|
|
167
|
+
error: null
|
|
168
|
+
});
|
|
169
|
+
React.useEffect(() => {
|
|
170
|
+
// Reset state when dependencies change
|
|
171
|
+
setResult({
|
|
172
|
+
value: defaultValue,
|
|
173
|
+
status: 'loading',
|
|
174
|
+
error: null
|
|
175
|
+
});
|
|
176
|
+
lastProcessedState.current = null;
|
|
177
|
+
const unsubscribe = ninetailed.onChangesChange(changesState => {
|
|
178
|
+
if (lastProcessedState.current && radash.isEqual(lastProcessedState.current, changesState)) {
|
|
179
|
+
experience_jsShared.logger.debug('Change State Did Not Change', changesState);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
lastProcessedState.current = changesState;
|
|
183
|
+
if (changesState.status === 'loading') {
|
|
184
|
+
// Don't use a function updater here to avoid type issues
|
|
185
|
+
setResult({
|
|
186
|
+
value: defaultValue,
|
|
187
|
+
status: 'loading',
|
|
188
|
+
error: null
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (changesState.status === 'error') {
|
|
193
|
+
setResult({
|
|
194
|
+
value: defaultValue,
|
|
195
|
+
status: 'error',
|
|
196
|
+
error: changesState.error
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
// Find the change with our flag key
|
|
202
|
+
const change = changesState.changes.find(change => change.key === flagKey);
|
|
203
|
+
if (change && change.type === experience_jsShared.ChangeTypes.Variable) {
|
|
204
|
+
const flagValue = change.value;
|
|
205
|
+
setResult({
|
|
206
|
+
value: flagValue,
|
|
207
|
+
status: 'success',
|
|
208
|
+
error: null
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
// Flag not found or wrong type, use default
|
|
212
|
+
setResult({
|
|
213
|
+
value: defaultValue,
|
|
214
|
+
status: 'success',
|
|
215
|
+
error: null
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
setResult({
|
|
220
|
+
value: defaultValue,
|
|
221
|
+
status: 'error',
|
|
222
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return unsubscribe;
|
|
227
|
+
}, [ninetailed, flagKey, defaultValue]);
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
|
|
137
231
|
const TrackHasSeenComponent = ({
|
|
138
232
|
children,
|
|
139
233
|
variant,
|
|
@@ -253,8 +347,8 @@ const MergeTag = ({
|
|
|
253
347
|
fallback
|
|
254
348
|
}) => {
|
|
255
349
|
const {
|
|
256
|
-
|
|
257
|
-
|
|
350
|
+
profile,
|
|
351
|
+
loading
|
|
258
352
|
} = useProfile();
|
|
259
353
|
if (loading || !profile) {
|
|
260
354
|
return null;
|
|
@@ -598,6 +692,7 @@ exports.NinetailedProvider = NinetailedProvider;
|
|
|
598
692
|
exports.Personalize = Personalize;
|
|
599
693
|
exports.TrackHasSeenComponent = TrackHasSeenComponent;
|
|
600
694
|
exports.useExperience = useExperience;
|
|
695
|
+
exports.useFlag = useFlag;
|
|
601
696
|
exports.useNinetailed = useNinetailed;
|
|
602
697
|
exports.usePersonalize = usePersonalize;
|
|
603
698
|
exports.useProfile = useProfile;
|
package/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { createContext, useMemo, useContext, useState, useRef, useEffect, createElement, forwardRef } from 'react';
|
|
2
2
|
import { Ninetailed, selectVariant, selectHasExperienceVariants } from '@ninetailed/experience.js';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { logger, isBrowser } from '@ninetailed/experience.js-shared';
|
|
4
|
+
import { logger, ChangeTypes, isBrowser } from '@ninetailed/experience.js-shared';
|
|
5
5
|
import { isEqual, get } from 'radash';
|
|
6
6
|
import { isForwardRef } from 'react-is';
|
|
7
7
|
|
|
@@ -77,33 +77,52 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const _excluded$3 = ["experiences"];
|
|
80
|
+
function formatProfileForHook(profile) {
|
|
81
|
+
const profileStateWithoutExperiences = _objectWithoutPropertiesLoose(profile, _excluded$3);
|
|
82
|
+
return Object.assign({}, profileStateWithoutExperiences, {
|
|
83
|
+
loading: profile.status === 'loading'
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Custom hook that provides access to the Ninetailed profile state
|
|
89
|
+
* with the 'experiences' property removed to prevent unnecessary re-renders.
|
|
90
|
+
*
|
|
91
|
+
* This hook handles profile state changes efficiently by:
|
|
92
|
+
* 1. Only updating state when actual changes occur
|
|
93
|
+
* 2. Removing the large 'experiences' object from the state
|
|
94
|
+
* 3. Properly cleaning up subscriptions when components unmount
|
|
95
|
+
*
|
|
96
|
+
* @returns The profile state without the 'experiences' property
|
|
97
|
+
*/
|
|
80
98
|
const useProfile = () => {
|
|
81
99
|
const ninetailed = useNinetailed();
|
|
82
|
-
const [
|
|
83
|
-
const profileStateRef = useRef({});
|
|
100
|
+
const [strippedProfileState, setStrippedProfileState] = useState(formatProfileForHook(ninetailed.profileState));
|
|
84
101
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* We use a ref to avoid an infinite loop which can happen when an empty profile state was updated with no changes.
|
|
88
|
-
* This behaviour occurred as the validation handling on the error property was not set properly in the "CreateProfile" and "UpdateProfile" endpoint types.
|
|
89
|
-
* Furthermore, it was also observed, that it "only" occurred when the preview plugin was used in parallel.
|
|
90
|
-
*/
|
|
102
|
+
// Reference to track the previous profile state for comparison
|
|
103
|
+
const profileStateRef = useRef(ninetailed.profileState);
|
|
91
104
|
useEffect(() => {
|
|
92
|
-
ninetailed.onProfileChange(
|
|
93
|
-
if
|
|
94
|
-
|
|
105
|
+
const unsubscribe = ninetailed.onProfileChange(changedProfileState => {
|
|
106
|
+
// Skip update if the profile hasn't actually changed
|
|
107
|
+
// Here we compare the entire profile including experiences and changes
|
|
108
|
+
if (isEqual(changedProfileState, profileStateRef.current)) {
|
|
109
|
+
logger.debug('Profile State Did Not Change', changedProfileState);
|
|
95
110
|
return;
|
|
96
|
-
} else {
|
|
97
|
-
setProfileState(profileState);
|
|
98
|
-
profileStateRef.current = profileState;
|
|
99
|
-
logger.debug('Profile State Changed', profileState);
|
|
100
111
|
}
|
|
112
|
+
profileStateRef.current = changedProfileState;
|
|
113
|
+
logger.debug('Profile State Changed', changedProfileState);
|
|
114
|
+
setStrippedProfileState(formatProfileForHook(changedProfileState));
|
|
101
115
|
});
|
|
116
|
+
|
|
117
|
+
// Clean up subscription when component unmounts
|
|
118
|
+
return () => {
|
|
119
|
+
if (typeof unsubscribe === 'function') {
|
|
120
|
+
unsubscribe();
|
|
121
|
+
logger.debug('Unsubscribed from profile state changes');
|
|
122
|
+
}
|
|
123
|
+
};
|
|
102
124
|
}, []);
|
|
103
|
-
|
|
104
|
-
return Object.assign({}, profileStateWithoutExperiences, {
|
|
105
|
-
loading: profileState.status === 'loading'
|
|
106
|
-
});
|
|
125
|
+
return strippedProfileState;
|
|
107
126
|
};
|
|
108
127
|
|
|
109
128
|
const usePersonalize = (baseline, variants, options = {
|
|
@@ -113,6 +132,83 @@ const usePersonalize = (baseline, variants, options = {
|
|
|
113
132
|
return selectVariant(baseline, variants, profile, options);
|
|
114
133
|
};
|
|
115
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Custom hook to retrieve a specific feature flag from Ninetailed changes.
|
|
137
|
+
*
|
|
138
|
+
* @param flagKey - The key of the feature flag to retrieve
|
|
139
|
+
* @param defaultValue - The default value to use if the flag is not found
|
|
140
|
+
* @returns An object containing the flag value and status information
|
|
141
|
+
*/
|
|
142
|
+
function useFlag(flagKey, defaultValue) {
|
|
143
|
+
const ninetailed = useNinetailed();
|
|
144
|
+
const lastProcessedState = useRef(null);
|
|
145
|
+
const [result, setResult] = useState({
|
|
146
|
+
value: defaultValue,
|
|
147
|
+
status: 'loading',
|
|
148
|
+
error: null
|
|
149
|
+
});
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
// Reset state when dependencies change
|
|
152
|
+
setResult({
|
|
153
|
+
value: defaultValue,
|
|
154
|
+
status: 'loading',
|
|
155
|
+
error: null
|
|
156
|
+
});
|
|
157
|
+
lastProcessedState.current = null;
|
|
158
|
+
const unsubscribe = ninetailed.onChangesChange(changesState => {
|
|
159
|
+
if (lastProcessedState.current && isEqual(lastProcessedState.current, changesState)) {
|
|
160
|
+
logger.debug('Change State Did Not Change', changesState);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
lastProcessedState.current = changesState;
|
|
164
|
+
if (changesState.status === 'loading') {
|
|
165
|
+
// Don't use a function updater here to avoid type issues
|
|
166
|
+
setResult({
|
|
167
|
+
value: defaultValue,
|
|
168
|
+
status: 'loading',
|
|
169
|
+
error: null
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (changesState.status === 'error') {
|
|
174
|
+
setResult({
|
|
175
|
+
value: defaultValue,
|
|
176
|
+
status: 'error',
|
|
177
|
+
error: changesState.error
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
// Find the change with our flag key
|
|
183
|
+
const change = changesState.changes.find(change => change.key === flagKey);
|
|
184
|
+
if (change && change.type === ChangeTypes.Variable) {
|
|
185
|
+
const flagValue = change.value;
|
|
186
|
+
setResult({
|
|
187
|
+
value: flagValue,
|
|
188
|
+
status: 'success',
|
|
189
|
+
error: null
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
// Flag not found or wrong type, use default
|
|
193
|
+
setResult({
|
|
194
|
+
value: defaultValue,
|
|
195
|
+
status: 'success',
|
|
196
|
+
error: null
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
setResult({
|
|
201
|
+
value: defaultValue,
|
|
202
|
+
status: 'error',
|
|
203
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
return unsubscribe;
|
|
208
|
+
}, [ninetailed, flagKey, defaultValue]);
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
|
|
116
212
|
const TrackHasSeenComponent = ({
|
|
117
213
|
children,
|
|
118
214
|
variant,
|
|
@@ -232,8 +328,8 @@ const MergeTag = ({
|
|
|
232
328
|
fallback
|
|
233
329
|
}) => {
|
|
234
330
|
const {
|
|
235
|
-
|
|
236
|
-
|
|
331
|
+
profile,
|
|
332
|
+
loading
|
|
237
333
|
} = useProfile();
|
|
238
334
|
if (loading || !profile) {
|
|
239
335
|
return null;
|
|
@@ -571,4 +667,4 @@ const ESRLoadingComponent = _ref => {
|
|
|
571
667
|
}));
|
|
572
668
|
};
|
|
573
669
|
|
|
574
|
-
export { DefaultExperienceLoadingComponent, ESRLoadingComponent, ESRProvider, Experience, MergeTag, NinetailedProvider, Personalize, TrackHasSeenComponent, useExperience, useNinetailed, usePersonalize, useProfile };
|
|
670
|
+
export { DefaultExperienceLoadingComponent, ESRLoadingComponent, ESRProvider, Experience, MergeTag, NinetailedProvider, Personalize, TrackHasSeenComponent, useExperience, useFlag, useNinetailed, usePersonalize, useProfile };
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninetailed/experience.js-react",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.12.0-beta.0",
|
|
4
4
|
"description": "Ninetailed SDK for React",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@ninetailed/experience.js": "7.
|
|
7
|
-
"@ninetailed/experience.js-shared": "7.
|
|
8
|
-
"@ninetailed/experience.js-plugin-analytics": "7.
|
|
6
|
+
"@ninetailed/experience.js": "7.12.0-beta.0",
|
|
7
|
+
"@ninetailed/experience.js-shared": "7.12.0-beta.0",
|
|
8
|
+
"@ninetailed/experience.js-plugin-analytics": "7.12.0-beta.0",
|
|
9
9
|
"radash": "10.9.0",
|
|
10
10
|
"react-is": "18.2.0"
|
|
11
11
|
},
|
package/src/lib/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type { NinetailedProviderProps, NinetailedProviderInstantiationProps, } f
|
|
|
5
5
|
export { useNinetailed } from './useNinetailed';
|
|
6
6
|
export { useProfile } from './useProfile';
|
|
7
7
|
export { usePersonalize } from './usePersonalize';
|
|
8
|
+
export { useFlag } from './useFlag';
|
|
8
9
|
export { Personalize } from './Personalize';
|
|
9
10
|
export type { PersonalizedComponent } from './Personalize';
|
|
10
11
|
export { MergeTag } from './MergeTag';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AllowedVariableType } from '@ninetailed/experience.js-shared';
|
|
2
|
+
export type FlagResult<T> = {
|
|
3
|
+
status: 'loading';
|
|
4
|
+
value: T;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
status: 'success';
|
|
8
|
+
value: T;
|
|
9
|
+
error: null;
|
|
10
|
+
} | {
|
|
11
|
+
status: 'error';
|
|
12
|
+
value: T;
|
|
13
|
+
error: Error;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Custom hook to retrieve a specific feature flag from Ninetailed changes.
|
|
17
|
+
*
|
|
18
|
+
* @param flagKey - The key of the feature flag to retrieve
|
|
19
|
+
* @param defaultValue - The default value to use if the flag is not found
|
|
20
|
+
* @returns An object containing the flag value and status information
|
|
21
|
+
*/
|
|
22
|
+
export declare function useFlag<T extends AllowedVariableType>(flagKey: string, defaultValue: T): FlagResult<T>;
|
package/src/lib/useProfile.d.ts
CHANGED
|
@@ -1,53 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { ProfileState } from '@ninetailed/experience.js';
|
|
2
|
+
type UseProfileHookResult = Omit<ProfileState, 'experiences'> & {
|
|
2
3
|
loading: boolean;
|
|
3
|
-
from: "api" | "hydrated";
|
|
4
|
-
status: "loading";
|
|
5
|
-
profile: null;
|
|
6
|
-
error: null;
|
|
7
|
-
} | {
|
|
8
|
-
loading: boolean;
|
|
9
|
-
from: "api" | "hydrated";
|
|
10
|
-
status: "success";
|
|
11
|
-
profile: {
|
|
12
|
-
id: string;
|
|
13
|
-
stableId: string;
|
|
14
|
-
random: number;
|
|
15
|
-
audiences: string[];
|
|
16
|
-
traits: import("@ninetailed/experience.js-shared").Properties;
|
|
17
|
-
location: {
|
|
18
|
-
coordinates?: {
|
|
19
|
-
latitude: number;
|
|
20
|
-
longitude: number;
|
|
21
|
-
} | undefined;
|
|
22
|
-
city?: string | undefined;
|
|
23
|
-
postalCode?: string | undefined;
|
|
24
|
-
region?: string | undefined;
|
|
25
|
-
regionCode?: string | undefined;
|
|
26
|
-
country?: string | undefined;
|
|
27
|
-
countryCode?: string | undefined;
|
|
28
|
-
continent?: string | undefined;
|
|
29
|
-
timezone?: string | undefined;
|
|
30
|
-
};
|
|
31
|
-
session: {
|
|
32
|
-
id: string;
|
|
33
|
-
isReturningVisitor: boolean;
|
|
34
|
-
landingPage: {
|
|
35
|
-
path: string;
|
|
36
|
-
url: string;
|
|
37
|
-
query: Record<string, string>;
|
|
38
|
-
referrer: string;
|
|
39
|
-
search: string;
|
|
40
|
-
};
|
|
41
|
-
count: number;
|
|
42
|
-
activeSessionLength: number;
|
|
43
|
-
averageSessionLength: number;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
error: null;
|
|
47
|
-
} | {
|
|
48
|
-
loading: boolean;
|
|
49
|
-
from: "api" | "hydrated";
|
|
50
|
-
status: "error";
|
|
51
|
-
profile: null;
|
|
52
|
-
error: Error;
|
|
53
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* Custom hook that provides access to the Ninetailed profile state
|
|
7
|
+
* with the 'experiences' property removed to prevent unnecessary re-renders.
|
|
8
|
+
*
|
|
9
|
+
* This hook handles profile state changes efficiently by:
|
|
10
|
+
* 1. Only updating state when actual changes occur
|
|
11
|
+
* 2. Removing the large 'experiences' object from the state
|
|
12
|
+
* 3. Properly cleaning up subscriptions when components unmount
|
|
13
|
+
*
|
|
14
|
+
* @returns The profile state without the 'experiences' property
|
|
15
|
+
*/
|
|
16
|
+
export declare const useProfile: () => UseProfileHookResult;
|
|
17
|
+
export {};
|