Skip to content

Instantly share code, notes, and snippets.

@nielk
Last active November 15, 2018 16:57
Show Gist options
  • Save nielk/7077bc6371e6e72d0876615e5a27ff07 to your computer and use it in GitHub Desktop.
Save nielk/7077bc6371e6e72d0876615e5a27ff07 to your computer and use it in GitHub Desktop.
import * as React from 'react'
import { Middleware } from 'redux'
// https://github.com/shiningjason/react-enhanced-reducer-hook
function compose(...fns: any): any {
if (fns.length === 0) {
return (arg: any) => arg
}
if (fns.length === 1) {
return fns[0]
}
return fns.reduce((a: any, b: any) => (...args: any) => a(b(...args)))
}
function useEnhancedReducer<S, A>(
reducer: React.Reducer<S, A>,
initialState: S,
middlewares: ReadonlyArray<Middleware> = [],
): any {
const hook = React.useState(initialState)
let state = hook[0]
const setState = hook[1]
const dispatch = (action: A) => {
state = reducer(state, action)
setState(state)
return action
}
let enhancedDispatch: (...args: any) => any
const store = {
getState: () => state,
dispatch: (...args: any) => enhancedDispatch(...args),
}
const chain = middlewares.map(middleware => middleware(store))
enhancedDispatch = compose.apply(void 0, chain)(dispatch)
return [state, enhancedDispatch]
}
export default useEnhancedReducer
function useAsync<E, A>(
asyncFn: () => Promise<E | A>,
props: React.InputIdentityList = [],
): [AsyncData<E, A>, () => void] {
const [result, setResult] = React.useState<AsyncData<E, A>>(NotLoaded<E, A>())
const execute = async () => {
setResult(Loading<E, A>())
try {
const res = await asyncFn()
setResult(Loaded<E, A>(res as A))
} catch (err) {
setResult(Failed<E, A>(err))
}
}
React.useEffect(() => {
execute()
}, props)
return [result, execute]
}
type NotLoaded = {
readonly _type: 'NotLoaded'
readonly data: undefined
}
export function NotLoaded<E, A>(): AsyncData<E, A> {
return {
_type: 'NotLoaded',
data: undefined,
}
}
type Loading<A> = {
readonly _type: 'Loading'
readonly data: A | undefined
}
export function Loading<E, A>(data?: A): AsyncData<E, A> {
return {
_type: 'Loading',
data,
}
}
type Failed<E, A> = {
readonly _type: 'Failed'
readonly error: E
readonly data: A | undefined
}
export function Failed<E, A>(error: E, data?: A): AsyncData<E, A> {
return {
_type: 'Failed',
error,
data,
}
}
type Loaded<A> = {
readonly _type: 'Loaded'
readonly data: A
}
export function Loaded<E, A>(data: A): AsyncData<E, A> {
return {
_type: 'Loaded',
data,
}
}
export type AsyncData<E = {}, A = {}> = NotLoaded | Loading<A> | Failed<E, A> | Loaded<A>
import * as React from 'react'
function usePrevious<T>(value: T, initialValue: T): T | null {
const ref = React.useRef<T | null>(initialValue)
React.useEffect(() => {
ref.current = value
})
return ref.current
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment