Skip to content

Commit f61f860

Browse files
authored
feat: skip unnecessary updates in SessionAuth (#831)
* feat: skip unnecessary updates in SessionAuth * chore: update version * chore: update size limit
1 parent 1ad1fcf commit f61f860

File tree

13 files changed

+108
-27
lines changed

13 files changed

+108
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
## [0.42.3] - 2024-07-19
11+
12+
### Changes
13+
14+
- Now we only update the session context if the object changes by value. This optimization should help reduce unnecessary re-renders.
15+
1016
## [0.42.2] - 2024-05-29
1117

1218
### Changes

examples/for-tests-react-16/src/App.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,14 @@ export const DashboardNoAuthRequired = doNotUseReactRouterDom
418418
export function DashboardNoAuthRequiredHelper(props) {
419419
let sessionContext = useSessionContext();
420420

421+
useEffect(() => {
422+
if (testContext.signoutOnSessionNotExists) {
423+
if (!sessionContext.loading && !sessionContext.doesSessionExist) {
424+
Session.signOut();
425+
}
426+
}
427+
}, [sessionContext]);
428+
421429
if (sessionContext.loading) {
422430
return null;
423431
}

examples/for-tests-react-16/src/testContext.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function getTestContext() {
2121
: undefined,
2222
enableMFA: localStorage.getItem("enableMFA") === "true",
2323
defaultToEmail: localStorage.getItem("defaultToEmail") !== "false",
24+
signoutOnSessionNotExists: localStorage.getItem("signoutOnSessionNotExists") === "true",
2425
disableRedirectionAfterSuccessfulSignInUp:
2526
localStorage.getItem("disableRedirectionAfterSuccessfulSignInUp") === "true",
2627
};

examples/for-tests/src/App.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,14 @@ export const DashboardNoAuthRequired = doNotUseReactRouterDom
590590
export function DashboardNoAuthRequiredHelper(props) {
591591
let sessionContext = useSessionContext();
592592

593+
useEffect(() => {
594+
if (testContext.signoutOnSessionNotExists) {
595+
if (!sessionContext.loading && !sessionContext.doesSessionExist) {
596+
Session.signOut();
597+
}
598+
}
599+
}, [sessionContext]);
600+
593601
if (sessionContext.loading) {
594602
return null;
595603
}

examples/for-tests/src/testContext.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function getTestContext() {
2222
},
2323
enableMFA: localStorage.getItem("enableMFA") === "true",
2424
defaultToEmail: localStorage.getItem("defaultToEmail") !== "false",
25+
signoutOnSessionNotExists: localStorage.getItem("signoutOnSessionNotExists") === "true",
2526
disableRedirectionAfterSuccessfulSignInUp:
2627
localStorage.getItem("disableRedirectionAfterSuccessfulSignInUp") === "true",
2728
};

lib/build/genericComponentOverrideContext.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/build/index2.js

Lines changed: 25 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/build/version.d.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ts/recipe/session/sessionAuth.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
6868
// Reusing the parent context was removed because it caused a redirect loop in an edge case
6969
// because it'd also reuse the invalid claims part until it loaded.
7070
const [context, setContext] = useState<SessionContextType>({ loading: true });
71+
const setContextIfChanged = useCallback(
72+
(newValue: SessionContextType) => {
73+
setContext((oldValue) => {
74+
// We can't do this check before re-validation because there are be validators that depend on the current time
75+
// Since the context is constructed by the same functions the property order should be stable, meaning that
76+
// a simple JSON string check should be sufficient.
77+
// Plus since this is just an optimization it is fine to have false positives,
78+
// and this method won't have false negatives (where we'd miss an update).
79+
if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
80+
return newValue;
81+
}
82+
return oldValue;
83+
});
84+
},
85+
[setContext]
86+
);
7187

7288
const session = useRef<Session>();
7389

@@ -191,7 +207,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
191207

192208
if (failureRedirectInfo.redirectPath !== undefined) {
193209
if (validateAndCompareOnFailureRedirectionURLToCurrent(failureRedirectInfo.redirectPath)) {
194-
setContext(toSetContext);
210+
setContextIfChanged(toSetContext);
195211
return;
196212
} else {
197213
return await SuperTokens.getInstanceOrThrow().redirectToUrl(
@@ -209,15 +225,15 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
209225
message: "Showing access denied screen because a claim validator failed",
210226
claimValidationError: failureRedirectInfo.failedClaim,
211227
});
212-
return setContext({
228+
return setContextIfChanged({
213229
...toSetContext,
214230
accessDeniedValidatorError: failureRedirectInfo.failedClaim,
215231
});
216232
}
217233
}
218234
}
219235

220-
setContext(toSetContext);
236+
setContextIfChanged(toSetContext);
221237
},
222238
[
223239
context.loading,
@@ -262,7 +278,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
262278
if (
263279
validateAndCompareOnFailureRedirectionURLToCurrent(failureRedirectInfo.redirectPath)
264280
) {
265-
setContext({ ...event.sessionContext, loading: false, invalidClaims });
281+
setContextIfChanged({ ...event.sessionContext, loading: false, invalidClaims });
266282
} else {
267283
return await SuperTokens.getInstanceOrThrow().redirectToUrl(
268284
failureRedirectInfo.redirectPath,
@@ -279,23 +295,23 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
279295
message: "Showing access denied screen because a claim validator failed",
280296
claimValidationError: failureRedirectInfo.failedClaim,
281297
});
282-
return setContext({
298+
return setContextIfChanged({
283299
...event.sessionContext,
284300
loading: false,
285301
invalidClaims,
286302
accessDeniedValidatorError: failureRedirectInfo.failedClaim,
287303
});
288304
}
289305
}
290-
setContext({ ...event.sessionContext, loading: false, invalidClaims });
306+
setContextIfChanged({ ...event.sessionContext, loading: false, invalidClaims });
291307

292308
return;
293309
}
294310
case "SIGN_OUT":
295-
setContext({ ...event.sessionContext, loading: false, invalidClaims: [] });
311+
setContextIfChanged({ ...event.sessionContext, loading: false, invalidClaims: [] });
296312
return;
297313
case "UNAUTHORISED":
298-
setContext({ ...event.sessionContext, loading: false, invalidClaims: [] });
314+
setContextIfChanged({ ...event.sessionContext, loading: false, invalidClaims: [] });
299315
if (props.onSessionExpired !== undefined) {
300316
props.onSessionExpired();
301317
} else if (props.requireAuth !== false && props.doRedirection !== false) {
@@ -316,7 +332,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
316332
return session.current.addEventListener(onHandleEvent);
317333
}
318334
return undefined;
319-
}, [props, setContext, context.loading, userContext, navigate, redirectToLogin]);
335+
}, [props, setContextIfChanged, context.loading, userContext, navigate, redirectToLogin]);
320336

321337
if (props.requireAuth !== false && (context.loading || !context.doesSessionExist)) {
322338
return null;

lib/ts/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
* License for the specific language governing permissions and limitations
1313
* under the License.
1414
*/
15-
export const package_version = "0.42.2";
15+
export const package_version = "0.42.3";

0 commit comments

Comments
 (0)