Skip to content

Instantly share code, notes, and snippets.

@webrgp
Last active September 29, 2022 20:54
Show Gist options
  • Save webrgp/a11e4f1c2dd4a1bdc9d7cafd3da9cb8d to your computer and use it in GitHub Desktop.
Save webrgp/a11e4f1c2dd4a1bdc9d7cafd3da9cb8d to your computer and use it in GitHub Desktop.

Some code snippets for easy store creation

// makeStore.ts - A function for creating more stores

import {
  Dispatch,
  Reducer,
  useContext,
  useReducer,
  createContext,
  ReactElement,
  PropsWithChildren
} from 'react'

const makeStore = <S, A>(
  reducer: Reducer<S, A>,
  initialState: S
): [
  ({
    children,
    defaultValues
  }: {
    children: ReactElement
    defaultValues: S
  }) => JSX.Element,
  () => Dispatch<A>,
  () => S
] => {
  const DispatchContext = createContext<Dispatch<A> | undefined>(undefined)
  const StoreContext = createContext<S | undefined>(undefined)

  type Props = {
    defaultValues: S
  }

  const StoreProvider = ({
    children,
    defaultValues = initialState
  }: PropsWithChildren<Props>) => {
    const [store, dispatch] = useReducer<Reducer<S, A>>(reducer, defaultValues)

    return (
      <DispatchContext.Provider value={dispatch}>
        <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
      </DispatchContext.Provider>
    )
  }

  const useDispatch = () => {
    const ctx = useContext(DispatchContext)
    if (ctx === undefined) {
      throw new Error('useDispatch must be used within a StoreProvider')
    }
    return ctx
  }
  const useStore = () => {
    const ctx = useContext(StoreContext)
    if (ctx === undefined) {
      throw new Error('useStore must be used within a StoreProvider')
    }
    return ctx
  }

  return [StoreProvider, useDispatch, useStore]
}

export default makeStore



// Sample usage

import makeStore from '@utils/makeStore'

type CraftAction =
  | { type: 'GET_CONTENT' }
  | { type: 'SET_CONTENT'; payload: any }

const craftReducer = (state: any, action: CraftAction) => {
  switch (action.type) {
    case 'GET_CONTENT':
      return state
    case 'SET_CONTENT':
      return action.payload
    default:
      return state
  }
}

const [CraftProvider, useCraftDispatch, useCraftStore] = makeStore(
  craftReducer,
  {}
)

export { CraftProvider, useCraftDispatch, useCraftStore }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment