Created
September 5, 2019 16:54
-
-
Save elsangedy/ef6c93de32a864cacbd35aaa29a213c6 to your computer and use it in GitHub Desktop.
useCombineReducer
This file contains hidden or 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
import { useMemo, useCallback, useReducer as useReducerBase } from "react"; | |
export function useCombineReducer(initialState, ...reducers) { | |
const internalReducer = useCallback( | |
(state, action) => ({ | |
...state, | |
...reducers.reduce( | |
(prev, current, idx) => | |
idx === 0 | |
? current(state, action, initialState) | |
: current(state, prev, action, initialState), | |
{} | |
) | |
}), | |
[reducers, initialState] | |
); | |
const [state, dispatch] = useReducerBase(internalReducer, initialState); | |
const customDispatch = useCallback( | |
(type, payload) => dispatch({ type, payload }), | |
[dispatch] | |
); | |
const values = useMemo(() => [state, customDispatch, dispatch], [ | |
state, | |
customDispatch, | |
dispatch | |
]); | |
return values; | |
} |
This file contains hidden or 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
import { useMemo, useEffect } from "react"; | |
import { useFetchMachine } from "./useFetchMachine"; | |
const delay = (ms = 300) => new Promise(resolve => setTimeout(resolve, ms)); | |
export function useFetch() { | |
function stateReducer(state, stateChanges, { type, payload }) { | |
switch (state.current) { | |
case "PENDING": | |
switch (type) { | |
case "RESOLVE": | |
stateChanges.data = payload; | |
break; | |
case "REJECT": | |
if (state.retries >= 3) { | |
stateChanges.current = "ERROR"; | |
} | |
break; | |
} | |
break; | |
case "FAILURE": | |
switch (type) { | |
case "RETRY": | |
stateChanges.current = "PENDING"; | |
stateChanges.retries = state.retries + 1; | |
break; | |
} | |
break; | |
} | |
return stateChanges; | |
} | |
const fetchMachine = useFetchMachine({ | |
stateReducer, | |
initialState: { | |
data: [], | |
retries: 0 | |
} | |
}); | |
const isPending = useMemo(() => fetchMachine.state.current === "PENDING", [ | |
fetchMachine.state.current | |
]); | |
const fetch = async () => { | |
await delay(1000); | |
fetchMachine.resolve([1, 2, 3, 4]); | |
}; | |
useEffect(() => { | |
if (isPending) { | |
fetch(); | |
} | |
}, [isPending]); | |
const retry = payload => fetchMachine.dispatch("RETRY", payload); | |
return { | |
...fetchMachine, | |
retry | |
}; | |
} |
This file contains hidden or 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
import { useCombineReducer } from "./useCombineReducer"; | |
function reducer(state, { type }, initialState) { | |
let stateChanges = {}; | |
switch (state.current) { | |
case "IDLE": | |
switch (type) { | |
case "FETCH": | |
stateChanges.current = "PENDING"; | |
break; | |
} | |
break; | |
case "PENDING": | |
switch (type) { | |
case "RESOLVE": | |
stateChanges.current = "SUCCESS"; | |
break; | |
case "REJECT": | |
stateChanges.current = "FAILURE"; | |
break; | |
} | |
break; | |
default: | |
switch (type) { | |
case "RESET": | |
stateChanges = { | |
...initialState | |
}; | |
break; | |
} | |
} | |
return stateChanges; | |
} | |
export const useFetchMachine = ({ | |
stateReducer = (_, newState) => newState, | |
initialState = {} | |
} = {}) => { | |
const [state, dispatch] = useCombineReducer( | |
{ | |
current: "IDLE", | |
...initialState | |
}, | |
reducer, | |
stateReducer | |
); | |
const fetch = payload => dispatch("FETCH", payload); | |
const resolve = payload => dispatch("RESOLVE", payload); | |
const reject = payload => dispatch("REJECT", payload); | |
const reset = payload => dispatch("RESET", payload); | |
return { | |
state, | |
fetch, | |
resolve, | |
reject, | |
reset, | |
dispatch | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment