Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Session] Use flag on state for persistence (#3793)

* Move isInitialLoad and isSwitchingAccounts out of main state

* Remove spreads, order object keys

* Track need to persist on state object

* Reoder state variables

authored by

dan and committed by
GitHub
df9af92e a6061489

+45 -48
+42 -43
src/state/session/index.tsx
··· 26 26 import { 27 27 SessionAccount, 28 28 SessionApiContext, 29 - SessionState, 30 29 SessionStateContext, 31 30 } from '#/state/session/types' 32 31 ··· 61 60 return __globalAgent 62 61 } 63 62 63 + type State = { 64 + accounts: SessionStateContext['accounts'] 65 + currentAccount: SessionStateContext['currentAccount'] 66 + needsPersist: boolean 67 + } 68 + 64 69 export function Provider({children}: React.PropsWithChildren<{}>) { 65 - const isDirty = React.useRef(false) 66 - const [state, setState] = React.useState<SessionState>({ 67 - isInitialLoad: true, 68 - isSwitchingAccounts: false, 70 + const [isInitialLoad, setIsInitialLoad] = React.useState(true) 71 + const [isSwitchingAccounts, setIsSwitchingAccounts] = React.useState(false) 72 + const [state, setState] = React.useState<State>({ 69 73 accounts: persisted.get('session').accounts, 70 74 currentAccount: undefined, // assume logged out to start 75 + needsPersist: false, 71 76 }) 72 77 73 - const setStateAndPersist = React.useCallback( 74 - (fn: (prev: SessionState) => SessionState) => { 75 - isDirty.current = true 76 - setState(fn) 77 - }, 78 - [setState], 79 - ) 80 - 81 78 const upsertAccount = React.useCallback( 82 79 (account: SessionAccount, expired = false) => { 83 - setStateAndPersist(s => { 80 + setState(s => { 84 81 return { 85 - ...s, 82 + accounts: [account, ...s.accounts.filter(a => a.did !== account.did)], 86 83 currentAccount: expired ? undefined : account, 87 - accounts: [account, ...s.accounts.filter(a => a.did !== account.did)], 84 + needsPersist: true, 88 85 } 89 86 }) 90 87 }, 91 - [setStateAndPersist], 88 + [setState], 92 89 ) 93 90 94 91 const clearCurrentAccount = React.useCallback(() => { 95 92 logger.warn(`session: clear current account`) 96 93 __globalAgent = PUBLIC_BSKY_AGENT 97 94 configureModerationForGuest() 98 - setStateAndPersist(s => ({ 99 - ...s, 95 + setState(s => ({ 96 + accounts: s.accounts, 100 97 currentAccount: undefined, 98 + needsPersist: true, 101 99 })) 102 - }, [setStateAndPersist]) 100 + }, [setState]) 103 101 104 102 const createPersistSessionHandler = React.useCallback( 105 103 ( ··· 260 258 async logContext => { 261 259 logger.debug(`session: logout`) 262 260 clearCurrentAccount() 263 - setStateAndPersist(s => { 261 + setState(s => { 264 262 return { 265 - ...s, 266 263 accounts: s.accounts.map(a => ({ 267 264 ...a, 268 265 refreshJwt: undefined, 269 266 accessJwt: undefined, 270 267 })), 268 + currentAccount: s.currentAccount, 269 + needsPersist: true, 271 270 } 272 271 }) 273 272 logEvent('account:loggedOut', {logContext}) 274 273 }, 275 - [clearCurrentAccount, setStateAndPersist], 274 + [clearCurrentAccount, setState], 276 275 ) 277 276 278 277 const initSession = React.useCallback<SessionApiContext['initSession']>( ··· 397 396 } catch (e) { 398 397 logger.error(`session: resumeSession failed`, {message: e}) 399 398 } finally { 400 - setState(s => ({ 401 - ...s, 402 - isInitialLoad: false, 403 - })) 399 + setIsInitialLoad(false) 404 400 } 405 401 }, 406 402 [initSession], ··· 408 404 409 405 const removeAccount = React.useCallback<SessionApiContext['removeAccount']>( 410 406 account => { 411 - setStateAndPersist(s => { 407 + setState(s => { 412 408 return { 413 - ...s, 414 409 accounts: s.accounts.filter(a => a.did !== account.did), 410 + currentAccount: s.currentAccount, 411 + needsPersist: true, 415 412 } 416 413 }) 417 414 }, 418 - [setStateAndPersist], 415 + [setState], 419 416 ) 420 417 421 418 const updateCurrentAccount = React.useCallback< 422 419 SessionApiContext['updateCurrentAccount'] 423 420 >( 424 421 account => { 425 - setStateAndPersist(s => { 422 + setState(s => { 426 423 const currentAccount = s.currentAccount 427 424 428 425 // ignore, should never happen ··· 443 440 } 444 441 445 442 return { 446 - ...s, 447 - currentAccount: updatedAccount, 448 443 accounts: [ 449 444 updatedAccount, 450 445 ...s.accounts.filter(a => a.did !== currentAccount.did), 451 446 ], 447 + currentAccount: updatedAccount, 448 + needsPersist: true, 452 449 } 453 450 }) 454 451 }, 455 - [setStateAndPersist], 452 + [setState], 456 453 ) 457 454 458 455 const selectAccount = React.useCallback<SessionApiContext['selectAccount']>( 459 456 async (account, logContext) => { 460 - setState(s => ({...s, isSwitchingAccounts: true})) 457 + setIsSwitchingAccounts(true) 461 458 try { 462 459 await initSession(account) 463 - setState(s => ({...s, isSwitchingAccounts: false})) 460 + setIsSwitchingAccounts(false) 464 461 logEvent('account:loggedIn', {logContext, withPassword: false}) 465 462 } catch (e) { 466 463 // reset this in case of error 467 - setState(s => ({...s, isSwitchingAccounts: false})) 464 + setIsSwitchingAccounts(false) 468 465 // but other listeners need a throw 469 466 throw e 470 467 } 471 468 }, 472 - [setState, initSession], 469 + [initSession], 473 470 ) 474 471 475 472 React.useEffect(() => { 476 - if (isDirty.current) { 477 - isDirty.current = false 473 + if (state.needsPersist) { 474 + state.needsPersist = false 478 475 persisted.write('session', { 479 476 accounts: state.accounts, 480 477 currentAccount: state.currentAccount, ··· 533 530 clearCurrentAccount() 534 531 } 535 532 536 - setState(s => ({ 537 - ...s, 533 + setState(() => ({ 538 534 accounts: session.accounts, 539 535 currentAccount: selectedAccount, 536 + needsPersist: false, // Synced from another tab. Don't persist to avoid cycles. 540 537 })) 541 538 }) 542 539 }, [state, setState, clearCurrentAccount, initSession]) ··· 544 541 const stateContext = React.useMemo( 545 542 () => ({ 546 543 ...state, 544 + isInitialLoad, 545 + isSwitchingAccounts, 547 546 hasSession: !!state.currentAccount, 548 547 }), 549 - [state], 548 + [state, isInitialLoad, isSwitchingAccounts], 550 549 ) 551 550 552 551 const api = React.useMemo(
+3 -5
src/state/session/types.ts
··· 3 3 4 4 export type SessionAccount = PersistedAccount 5 5 6 - export type SessionState = { 7 - isInitialLoad: boolean 8 - isSwitchingAccounts: boolean 6 + export type SessionStateContext = { 9 7 accounts: SessionAccount[] 10 8 currentAccount: SessionAccount | undefined 11 - } 12 - export type SessionStateContext = SessionState & { 9 + isInitialLoad: boolean 10 + isSwitchingAccounts: boolean 13 11 hasSession: boolean 14 12 } 15 13 export type SessionApiContext = {