In order to setup a context when using React hooks related to a Redux store (e.g. useDispatch, useSelector) you need to have your component nested inside of a "Provider" component (from the react-redux package).
This isn't always possible as not all applications are built as a single "app" with components nested under a single root. In my case I am using ReactJs.Net together with a CMS to allow the end user to defined any combination of a number of pre-defined "components" on a page.
It turns out that you don't need all components to be nested inside of the same "Provider" instance, as long as the "store" itself is a singleton then you can have many "Provider" instances on the page all sharing the same "store".
I wanted an easy way to start wrapping my existing components in a "Provider" component without having to change too much about my non-Redux application structure. What I came up with was creating a simple high order component as a function and then simply wrapping my exported component with a call to the HOC when I want to wrap it with the Redux provider, e.g.
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
export const withReduxStore = Component => ({ ...props }) =>
(<Provider store={store}><Component {...props} /></Provider>)
This assumes you have singleton store, for example:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './ducks/rootReducer'
const store = createStore(rootReducer, applyMiddleware(thunk));
export { store };
And now to update a component that previously didn't have access to the store context and give it access:
import React from 'react';
import { useDispatch } from 'react-redux';
import { withReduxStore } from './state/withReduxStore.jsx';
const MyExampleComponent = (props) => {
const dispatch = useDispatch();
return <>
<button onClick={() => dispatch({hello: "world"})} type="button">Dispatch Something</button>
</>
}
export default withReduxStore(MyExampleComponent); <-- simply wrap it with a call to "withReduxStore"