Skip to content

Instantly share code, notes, and snippets.

@tannerlinsley
Last active July 8, 2024 07:06
Show Gist options
  • Select an option

  • Save tannerlinsley/a40e0206627cbf3824f0e32bbd586dad to your computer and use it in GitHub Desktop.

Select an option

Save tannerlinsley/a40e0206627cbf3824f0e32bbd586dad to your computer and use it in GitHub Desktop.

Revisions

  1. tannerlinsley revised this gist Jan 18, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.js
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ import { render } from 'react-dom'
    import Store from './store'

    // Import any initialState
    import { initialState as count } from './store.Count
    import { initialState as count } from './store.Count'

    // Import components
    import Counter from './Counter'
  2. tannerlinsley created this gist Jan 18, 2019.
    16 changes: 16 additions & 0 deletions Counter.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    import { useCount, useIncrement, useDecrement } from './store.Count'

    export default function Counter () {
    const count = useCount()
    const increment = useIncrement()
    const decrement = useDecrement()

    return (
    <div>
    <div>Count: {count}</div>
    <div>
    <button onClick={increment}>Increment</button>
    <button onClick={decrement}>Decrement</button>
    </div>
    )
    }
    23 changes: 23 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    import React from 'react'
    import { render } from 'react-dom'

    // Import the store
    import Store from './store'

    // Import any initialState
    import { initialState as count } from './store.Count
    // Import components
    import Counter from './Counter'

    // Build initial state
    const initialState = {
    count
    }

    render(
    // Use the Store Provider
    <Store.Provider initialState={initialState}>
    <Counter />
    </Store.Provider
    )
    38 changes: 38 additions & 0 deletions makeStore.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    import React, { useState, useMemo, useCallback, useContext } from 'react'
    import immer from 'immer' // Immer rocks. Go check it out if you haven't

    export default function makeStore() {
    // This is basically a factory for a new store instance

    // Create a new context for this store instance
    const context = React.createContext()

    // Make a provider that takes an initial state
    const Provider = ({ children, initialState = {} }) => {

    // useState will do. Nothing fancy needed
    const [state, preSetState] = useState(initialState)

    // We make our own setState callback that uses immer under the hood
    // (or we could use `useImmer`, but this is fun, too)
    const setState = useCallback(
    updater => preSetState(old => immer(old, draft => updater(draft))),
    preSetState
    )

    // Memoize the context value so it only updates when the state changes
    const contextValue = useMemo(() => [state, setState], [state])

    // Pass the context down
    return <context.Provider value={contextValue}>{children}</context.Provider>
    }

    // A hook to consume the context. No need to import `useContext` everywhere. How wasteful...
    const useStore = () => useContext(context)

    // Export them however you like. I prefer a default.
    return {
    Provider,
    useStore,
    }
    }
    23 changes: 23 additions & 0 deletions store.Count.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    import Store from './'

    // Export our initial state
    export const initialState = 0

    export function useCount () {
    const [{ count }] = Store.useStore()
    return count
    }

    export function useIncrement () {
    const [_, setState] = Store.useStore()
    return () => setState(draft => {
    draft.count++
    })
    }

    export function useDecrement () {
    const [_, setState] = Store.useStore()
    return () => setState(draft => {
    draft.count--
    })
    }
    5 changes: 5 additions & 0 deletions store.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    // Import our factory
    import makeStore from './makeStore'

    // Export a new state instance
    export default makeStore()