Last active
March 1, 2019 10:56
-
-
Save vandycknick/3bbc097993ba602856c5880220108eda to your computer and use it in GitHub Desktop.
React Hook recipe to access state and dispatch redux actions. Demo: https://codesandbox.io/s/8n1o5n135l
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
import { createContext, useContext, useEffect, useRef, useState } from 'react'; | |
import shallowEqual from 'shallowequal'; | |
const StoreContext = createContext(null); | |
const Provider = StoreContext.Provider; | |
const useDispatch = () => { | |
// Get the provided store from the current StoreContext | |
const store = useContext(StoreContext); | |
// Throw an error when hook is used without being wrapped in a redux provider context | |
if (!store) | |
throw new Error( | |
'A redux store should be provided via the useRedux Provider component. <Provider value={store} />' | |
); | |
// Return redux store dispatch function | |
return store.dispatch; | |
}; | |
const useRedux = () => { | |
// Get the provided store from the current StoreContext | |
const store = useContext(StoreContext); | |
// Throw an error when hook is used without being wrapped in a redux provider context | |
if (!store) | |
throw new Error( | |
'A redux store should be provided via the useRedux Provider component. <Provider value={store} />' | |
); | |
// Store the current state | |
const [currentState, setCurrentState] = useState(store.getState()); | |
// Keep a reference to the previous state | |
const previousState = useRef(currentState); | |
// Monitor for changes to the store and than resubscribe | |
useEffect( | |
() => { | |
let didUnsubscribe = false; | |
// Redux update function, run on each store update | |
const checkForUpdates = () => { | |
if (didUnsubscribe) return; | |
const newState = store.getState(); | |
// Check if the new state is different from the last saved state | |
// If so change the current state | |
if (!shallowEqual(newState, previousState.current)) { | |
setCurrentState(newState); | |
previousState.current = newState; | |
} | |
}; | |
checkForUpdates(); | |
const unsubscribe = store.subscribe(checkForUpdates); | |
const unsubscribeWrapper = () => { | |
didUnsubscribe = true; | |
unsubscribe(); | |
}; | |
// Unsubscribe from redux store updates when component goes out of scope | |
return unsubscribeWrapper; | |
}, | |
[store] | |
); | |
// Return the current state | |
return currentState; | |
}; | |
export { Provider, useRedux, useDispatch }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment