Skip to content

Instantly share code, notes, and snippets.

@vandycknick
Last active March 1, 2019 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vandycknick/3bbc097993ba602856c5880220108eda to your computer and use it in GitHub Desktop.
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
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