-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
share revalidation logic between session and cart
- Loading branch information
Showing
5 changed files
with
98 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,35 @@ | ||
import React, { useEffect } from 'react' | ||
import React, { createContext, useMemo } from 'react' | ||
import type { PropsWithChildren } from 'react' | ||
|
||
import { useContext } from '../utils/useContext' | ||
import { Context } from './Session' | ||
import { createUseValidationHook } from '../utils/useValidation' | ||
import { Context as SessionContext } from './Session' | ||
import type { Session } from './Session' | ||
|
||
export interface Props { | ||
onValidateSession?: (session: Session) => Promise<Session | null> | ||
} | ||
|
||
// Validation queue | ||
let queue = Promise.resolve() | ||
export const Context = createContext<boolean | undefined>(undefined) | ||
|
||
const useValidation = createUseValidationHook() | ||
|
||
export const RevalidateProvider = ({ | ||
onValidateSession, | ||
children, | ||
}: PropsWithChildren<Props>) => { | ||
const { setSession, ...session } = useContext(Context) | ||
|
||
useEffect(() => { | ||
let cancel = false | ||
|
||
const revalidate = async () => { | ||
if (cancel || onValidateSession == null) { | ||
return | ||
} | ||
|
||
const newSession = await onValidateSession(session) | ||
|
||
if (cancel) { | ||
return | ||
} | ||
|
||
if (newSession != null) { | ||
setSession(newSession) | ||
} | ||
} | ||
const context = useContext(SessionContext) | ||
const session = useMemo(() => { | ||
const { setSession, ...rest } = context | ||
|
||
// Enqueue validation | ||
setTimeout(() => { | ||
queue = queue.then(revalidate) | ||
}, 0) | ||
return rest | ||
}, [context]) | ||
|
||
return () => { | ||
cancel = true | ||
} | ||
}, [onValidateSession, session, setSession]) | ||
const isValidating = useValidation({ | ||
onValidate: onValidateSession, | ||
value: session, | ||
setValue: context.setSession, | ||
}) | ||
|
||
return <>{children}</> | ||
return <Context.Provider value={isValidating}>{children}</Context.Provider> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,13 @@ | ||
import { Context } from './Session' | ||
import { Context as SessionContext } from './Session' | ||
import { Context as ValidationContext } from './Revalidate' | ||
import { useContext } from '../utils/useContext' | ||
|
||
export const useSession = () => useContext(Context) | ||
export const useSession = () => { | ||
const session = useContext(SessionContext) | ||
const isValidating = useContext(ValidationContext) | ||
|
||
return { | ||
...session, | ||
isValidating, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { useEffect, useState } from 'react' | ||
|
||
interface Options<T> { | ||
onValidate?: (value: T) => Promise<T | null> | ||
value: T | ||
setValue: (value: T) => void | ||
} | ||
|
||
const nullable = async () => null | ||
|
||
export const createUseValidationHook = () => { | ||
// Validation queue | ||
let queue = Promise.resolve() | ||
|
||
const useValidation = <T>({ | ||
onValidate = nullable, | ||
value, | ||
setValue, | ||
}: Options<T>) => { | ||
const [isValidating, setIsValidating] = useState(true) | ||
|
||
useEffect(() => { | ||
let cancel = false | ||
|
||
const revalidate = async () => { | ||
if (cancel) { | ||
return | ||
} | ||
|
||
setIsValidating(true) | ||
const newValue = await onValidate(value) | ||
|
||
if (cancel) { | ||
return | ||
} | ||
|
||
setIsValidating(false) | ||
if (newValue != null) { | ||
setValue(newValue) | ||
} | ||
} | ||
|
||
// Enqueue validation | ||
setTimeout(() => { | ||
queue = queue.then(revalidate) | ||
}, 0) | ||
|
||
return () => { | ||
cancel = true | ||
} | ||
}, [onValidate, setValue, value]) | ||
|
||
return isValidating | ||
} | ||
|
||
return useValidation | ||
} |