Last active
July 7, 2019 01:54
-
-
Save Landerson352/3134abae5c981d6763398d54522c61a5 to your computer and use it in GitHub Desktop.
createAppState: Lean app state management for small React apps, using hooks and immer. (after copying files: yarn add immer lodash)
This file contains 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
// Wrap your app with your provider, and place components inside it | |
import React from 'react'; | |
import {AppStateProvider} from './useAppState'; | |
import MyComponent from './MyComponent'; | |
const App = () => ( | |
<AppStateProvider> | |
<MyComponent /> | |
</AppStateProvider> | |
); | |
export default App; |
This file contains 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
// This utility module can be used in any project | |
import React, {createContext, useContext, useReducer} from 'react'; | |
import produce from 'immer'; | |
import {mapValues} from 'lodash'; | |
const createAppState = (initialState = {}, mutators = {}) => { | |
const Context = createContext({}); | |
// create provider | |
// sets initial state and uses Immer *as* the reducer | |
const AppStateProvider = ({children}) => ( | |
<Context.Provider value={useReducer(produce, initialState)}> | |
{children} | |
</Context.Provider> | |
); | |
// create hook | |
// wraps each function with dispatch and injects state so that Immer can receive it | |
const useAppState = () => { | |
const [state, dispatch] = useContext(Context); | |
const mutatorsWithDispatch = mapValues(mutators, (mutator) => (...args) => { | |
return dispatch((state) => mutator(state, ...args)); | |
}); | |
return [state, mutatorsWithDispatch]; | |
}; | |
return [AppStateProvider, useAppState]; | |
}; | |
export default createAppState; |
This file contains 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
// Components like this one can access state and mutators, if they are used within the provider | |
import React from 'react'; | |
import useAppState from './useAppState'; | |
const MyComponent = () => { | |
// consume and modify state like so: | |
const [{name}, {setName}] = useAppState(); | |
return ( | |
<div> | |
<p>Your name is {name}.</p> | |
<button onClick={() => setName('Bob')}>My name is Bob!</button> | |
</div> | |
); | |
}; | |
export default MyComponent; |
This file contains 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
// Define your application's intitial state and actions which may mutate it | |
import createAppState from './createAppState'; | |
const initialState = { | |
name: 'Unknown', | |
}; | |
const mutators = { | |
setName: (state, name) => { | |
// immer's "draft" state is frontloaded in the argument list, so you can manipulate it directly | |
state.name = name; | |
}, | |
}; | |
export const [AppStateProvider, useAppState] = createAppState(initialState, mutators); | |
export default useAppState; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment