Skip to content

Instantly share code, notes, and snippets.

@mpriour
Created October 20, 2020 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpriour/69cea28ae7a5bb10f6a08587309ef309 to your computer and use it in GitHub Desktop.
Save mpriour/69cea28ae7a5bb10f6a08587309ef309 to your computer and use it in GitHub Desktop.
async reducer example
import { Context, createContext, h } from "preact";
import { useMemo } from "preact/hooks";
import { UserSession } from "@esri/arcgis-rest-auth";
import useLocalStorageState from "../hooks/useLocalStorageState";
import useAsyncReducer from "../hooks/useAsyncReducer";
interface IProviderProps {
children?:any
}
enum AuthActions {
read = 'READ_SESSION',
write = 'WRITE_SESSION',
start = 'START_SESSION',
end = 'END_SESSION'
}
type AuthActionTypes = keyof typeof AuthActions
interface IContextProps {
auth: UserSession,
dispatch: (action: AuthActionTypes) => Promise<void>
}
const authReducer = (state: UserSession, action: AuthActionTypes) => {
const [serializedSession, setSerializedSession] = useLocalStorageState('_AGO_SESSION_', null)
switch (action) {
case "read":
if(serializedSession){
// If there is a serialized session, parse it and set state
let parsed = JSON.parse(serializedSession)
// Cast the tokenExpires property back into a date.
parsed.tokenExpires = new Date(parsed.tokenExpires)
return new Promise<UserSession>(resolve => {resolve(new UserSession(parsed))})
}
return new Promise<UserSession>((resolve, reject)=>{reject('Saved session not available')})
case "write":
const serialized = state.serialize()
setSerializedSession(serialized)
return new Promise<UserSession>(resolve => {resolve(state)})
case "start":
if(serializedSession){
// If there is a serialized session, parse it and set state
let parsed = JSON.parse(serializedSession)
// Cast the tokenExpires property back into a date.
parsed.tokenExpires = new Date(parsed.tokenExpires)
if(parsed.tokenExpires > new Date()){
return new Promise<UserSession>(resolve => {resolve(new UserSession(parsed))})
}
}
return UserSession.beginOAuth2({
clientId: 'arcgisonline',
redirectUri: window.location.href,
portal: 'https://devext.arcgis.com/sharing/rest',
popup: false
}).then(session => {
setSerializedSession(session.serialize())
return session
})
case "end":
setSerializedSession(null)
return new Promise<UserSession>(resolve => {resolve({} as UserSession)})
default:
return new Promise<UserSession>((resolve, reject) => {reject('No valid action specified')})
}
}
const AuthContext = createContext({} as IContextProps) as Context<IContextProps>
function AuthProvider({children}: IProviderProps){
const [auth, dispatch] = useAsyncReducer<UserSession,AuthActionTypes>(authReducer, {} as UserSession)
const contextObj = useMemo(()=>({auth, dispatch} as IContextProps), [auth])
return (
<AuthContext.Provider value={contextObj}>
{children}
</AuthContext.Provider>
)
}
export {AuthContext, AuthProvider}
import { useState } from "preact/hooks"
function useAsyncReducer<S,A>(reducer:(prevState: S, action: A) => Promise<S>, initialState:S){
const [state, setState] = useState<S>(initialState);
const dispatch = async (action:A) => {
const result = reducer(state, action);
if (typeof result.then === "function") {
try {
const newState = await result;
setState(newState);
} catch (err) {
setState({ ...state, error: err });
}
}/* else {
setState(result as S);
} */
};
return [state, dispatch];
};
export default useAsyncReducer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment