19

I have a NextJS React app that uses the next-react-wrapper (basically a HOC) on _app.tsx like so:

_app.tsx

...
import withRedux from 'next-redux-wrapper';

class Page extends App<Props> {
  ...
}

export default withRedux(reduxStore)(Page);

store.ts

import { applyMiddleware, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';

import rootReducer from './reducer';

export default (
  initialState: any = undefined,
) => createStore(
  rootReducer,
  initialState,
  composeWithDevTools(applyMiddleware()),
);

I'm struggling to work out how to access the store outside of React such as in a simple helper function. My store.ts file exports a makeStore function which is needed (including the initial state) for the next-redux-wrapper HOC.

I could access the store in a React component and pass it to my helper functions as an argument each time but that seems messy.

Is there a way to access the store direct from non React helper function modules?

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
CaribouCode
  • 13,998
  • 28
  • 102
  • 174

6 Answers6

4

It may not be preferable, but the store can be accessed from the window using a storeKey. The default key is __NEXT_REDUX_STORE__ and using it look like this:

window.__NEXT_REDUX_STORE__.getState()

Here's where that happens

The key (storeKey) can be changed in the second options parameter passed to the withRedux function parameter. For your implementation it looks like this:

export default (
  initialState: any = undefined,
  { storeKey: 'whateveryouwant' } // the name on the exposed store variable
) => createStore(
  rootReducer,
  initialState,
  composeWithDevTools(applyMiddleware()),
);
Scott Powell
  • 392
  • 2
  • 6
  • Is there any way to access it from server side because window becomes undefined – Abanoub Istfanous Feb 27 '20 at 00:48
  • For a statically compiled app (using `next export`), would the store's state be reset on every refresh? If so... how does one fix that issue? – 7ball Oct 12 '20 at 09:24
  • @7ball yes and that will be the case for a SSR and SSG (static) site. The most popular solution to this is using a state-persistence library (e.g. redux-persist). – Scott Powell Oct 15 '20 at 04:08
4

I had the same issue but found the solution.

The Readme of this lib gives the example of makeStore function like this:

const makeStore = (initialState, options) => {
    return createStore(reducer, initialState);
};

You need to modify it a bit

let store;
const makeStore = (initialState, options) => {
    store = createStore(reducer, initialState);
return store;
};

export {store}

Now you can import the store from wherever you want.

Viacheslav Luschinskiy
  • 1,309
  • 1
  • 10
  • 8
3

Worked for me with TS

let store: ReturnType<typeof configStore>

const configStore = () => configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunkMiddleware),
  devTools: process.env.NODE_ENV !== 'production',
});

export const makeStore = () => {
  store = configStore();
  return store;
};

export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<typeof combinedReducer>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Action>;
export type AppDispatch = ReturnType<AppStore['dispatch']>;

export const wrapper = createWrapper<AppStore>(makeStore, { debug: false });

export { store };
Slackbvp
  • 31
  • 3
-1

You can create high-order function to wrap any other function with store. Here is simple example that pass store as this argument to any other function.

function withReduxFunction(store) {
    return function (connectedFunction) {
        return function (...args) {
            connectedFunction.call(store, ...args);
        }
    }
}

And usage. For example we want to provide store to this function

function doSomthingWothStore(arg1, arg2) {
    console.log(this);   // This will be store
    console.log("arg1: " + arg1 + " arg2 " + arg2);
}

Do

const funcWithStore = withReduxFunction(store)(doSomthingWothStore);

Now you can call funcWithStore and this will be equal to store.

You can play with high-order function to make it suitable for you (i.e. pass store as first argument and so on).

Also you can take a look at useDispatch and useSelector hooks from react-redux. They also should work with any function.

Fyodor Yemelyanenko
  • 11,264
  • 1
  • 30
  • 38
  • Isn't this basically the same as accessing store from the React component and passing it as an argument to my function manually? – CaribouCode Jun 28 '19 at 13:51
  • This is somewhat similar to how component is conected to store with `withRedux`. You connect once, and then call it many times without explicitly passing the store – Fyodor Yemelyanenko Jun 28 '19 at 21:38
-3

You can import store module wherever it is needed and directly access the store functions like store.getState(). However, you need to subscribe to store to be notified of any change in the state.

Aditya
  • 771
  • 5
  • 11
  • I'm not sure how I would import store to a function in my scenario. The store is created inside a function and via next-with-redux HOC. I don't see an easy way to import the store... – CaribouCode Jun 28 '19 at 13:49
  • You have to export the store from the module where it is instantiated and import that module everywhere. – Aditya Jul 01 '19 at 05:37
  • How can I export it when it doesn't get initialised until its wrapping function is called? This is how next-with-redux HOC works. – CaribouCode Jul 02 '19 at 17:51
-3

You can create store first and then return it from makeStore()

export const store = createStore(...)
const makeStore() {
  return store
}
export const wrapper = createWrapper(makeStore, { debug: true })