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?
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()),
);
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.
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 };
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.
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.
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 })
Related
What am I trying to do?
Using Redux Toolkit, I'm trying to access the "store" for a value, specifically "username" which I've created a "slice" for, from a non-React file called SomeFile.js.
What is the code that currently tries to do that?
// userMetadataSlice.js
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
username: "",
};
const userMetadataSlice = createSlice({
name: "userMetadata",
initialState,
reducers: {
updateUsername: (state, action) => {
const username = action.payload;
state.username = username;
},
},
});
export const { updateUsername } = userMetadataSlice.actions;
export default userMetadataSlice.reducer;
export const selectUsername = (state) => {
return state.userMetadata.username;
}
// SomeFile.js
import { selectUsername } from "../redux/userMetadataSlice";
import { useSelector } from "react-redux";
export const displayUsername = () => {
const username = useSelector(selectUsername);
console.log("Username:", username); // Error.
}
What do I expect the result to be?
To be able to pull the username from the "store".
What is the actual result?
When I try to access the value via "useSelector" from the non-react file an error occurs: React Hook "useSelector" is called in function "selectUsername" which is neither a React function component or a custom React Hook function
What I think the problem could be?
SomeFile.js does not have anything React related within it because it just pulls data from the store and outputs the data.
A solution I've tried that worked was to do this:
// userMetadataSlice.js
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
username: "",
};
const userMetadataSlice = createSlice({
name: "userMetadata",
initialState,
reducers: {
updateUsername: (state, action) => {
const username = action.payload;
state.username = username;
},
},
});
export const { updateUsername } = userMetadataSlice.actions;
export default userMetadataSlice.reducer;
export const selectUsername = (state) => {
return state.userMetadata.username;
}
// New code here!
export function SelectUsername() {
const username = useSelector(selectUsername);
return username;
}
// SomeFile.js
import { SelectUsername } from "../redux/userMetadataSlice";
export const displayUsername = () => {
console.log("Username:", SelectUsername); // No errors, shows correct output.
}
The solutions I'm looking for is this:
Is my proposed solution the "proper" way to receive info from the "store" in non-React files?
Is there a custom hook solution for this?
Is my proposed solution the "proper" way to receive info from the
"store" in non-React files?
No, it's abusing the Rules of Hooks and React functions. You are directly invoking the SelectUsername React function.
Is there a custom hook solution for this?
No, React hooks work only in React functions and custom React hooks.
You can access your state from your Redux store object.
Store
From your created store object you'll have a getState method to invoke.
getState()
Returns the current state tree of your application. It is equal to the
last value returned by the store's reducer.
Returns
(any): The current state tree of your application.
You can export your created store object for import into non-React JS files and they can invoke the getStore method.
import store from '../path/to/store';
...
const state = store.getState();
The useSelector React hook from react-redux won't work outside a React component, but the selectUsername state selector function will.
// SomeFile.js
import store from '../path/to/store';
import { selectUsername } from "../redux/userMetadataSlice";
...
export const displayUsername = () => {
const state = store.getState();
const username = selectUsername(state);
console.log("Username:", username);
return username;
};
See the other Store Methods for subscribing to state changes and dispatching actions to your store from outside React.
Follow the official example to export your own useStore, and then use it in the component.
import { createStore, Store, useStore as baseUseStore } from 'vuex';
export const key: InjectionKey<Store<RootState>> = Symbol();
export function useStore() {
return baseUseStore(key);
}
use in the component
setup() {
const store = useStore();
const onClick = () => {
console.log(store)
store.dispatch('user/getUserInfo');
}
return {
onClick,
}
},
After running, store is undefined.
It can be obtained normally when I use it in the methods attribute
methods: {
login() {
this.$store.dispatch('user/getToken')
}
}
why? how to fix it
In that simplifying useStore usage tutorial, you still need to register the store and key in main.ts as they did. You will get undefined if you don't do this:
// main.ts
import { store, key } from './store'
const app = createApp({ ... })
// pass the injection key
app.use(store, key)
The reason is that baseUseStore(key) has no meaning until that's done.
As part of my ongoing project to learn React (I'm natively an ASP.NET guy) I've hit this issue. I have a suite of React apps in which I want to use some common UI elements, so I've attempted to break these out into a separate npm package. For the shared components themselves this has worked fine.
However, some of these components depend on redux actions to operate, so I've tried to bundle these actions and a reducer function into the external package. Here's a simplified version of my actions\index.js:
export const SNACKBAR_MESSAGE = "SNACKBAR_MESSAGE";
export const SNACKBAR_HIDE = "SNACKBAR_HIDE";
export function showSnackBarMessage(message) {
console.log('hit 1');
return (dispatch, getState) => {
console.log('hit 2');
dispatch(hideSnackBar());
dispatch({
type: SNACKBAR_MESSAGE,
message: message
});
}
}
export const hideSnackBar = () => {
type: SNACKBAR_HIDE
};
And this is reducer\index.js:
import {
SNACKBAR_MESSAGE,
SNACKBAR_HIDE
} from "../actions";
const initialState = {
snackBarMessage: null,
snackBarVisible: false
};
export default function UiReducer(state = initialState, action) {
switch(action.type) {
case SNACKBAR_MESSAGE:
return Object.assign({}, state, {
snackBarMessage: action.message,
snackBarVisible: true
});
case SNACKBAR_HIDE:
return Object.assign({}, state, {
snackBarMessages: '',
snackBarVisible: false
});
default:
return state;
}
}
This is the same code that worked fine when part of the original project. These are exported by my package's entry point file like this:
// Reducer
export { default as uiReducer } from './reducer';
// Actions
export { showSnackBarMessage as uiShowPrompt } from './actions';
export { hideSnackBar as uiHidePrompt } from './actions';
Then in my consuming project, my default reducer looks like this:
import { routerReducer } from 'react-router-redux';
import { combineReducers } from 'redux';
import { uiReducer } from 'my-custom-ui-package';
// Import local reducers
const reducer = combineReducers(
{
// Some local reducers
ui: uiReducer
}
);
export default reducer;
The problem is when I try to dispatch one of these actions imported from my external package. I include the action, e.g. import { uiShowPrompt } from "my-custom-ui-package"; and dispatch it like dispatch(uiShowPrompt("Show me snackbar")); then I see the two console messages (hit 1 and hit 2) displayed, but then the following error:
Uncaught TypeError: Cannot read property 'type' of undefined
at store.js:12
at dispatch (applyMiddleware.js:35)
at my-custom-ui-package.js:1
at index.js:8
at middleware.js:22
at store.js:15
at dispatch (applyMiddleware.js:35)
at auth.js:28
at index.js:8
at middleware.js:22
The store itself looks like this:
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from 'redux-thunk';
import { browserHistory } from "react-router";
import {
syncHistoryWithStore,
routerReducer,
routerMiddleware
} from "react-router-redux";
import reducer from "./reducer";
const loggerMiddleware = store => next => action => {
console.log("Action type:", action.type);
console.log("Action payload:", action.payload);
console.log("State before:", store.getState());
next(action);
console.log("State after:", store.getState());
};
const initialState = {};
const createStoreWithMiddleware = compose(
applyMiddleware(
loggerMiddleware,
routerMiddleware(browserHistory),
thunk)
)(createStore);
const store = createStoreWithMiddleware(reducer, initialState);
export default store;
I'm afraid I don't understand this error. I don't see what I'm doing differently other than essentially moving identical code from my local project to an npm package. Since neither the actions nor reducer actually depend on redux, my npm package doesn't itself have a dependency on react-redux. Is that a problem? If there's anything else I could share to help you help me just let me know. Like I say, I'm still fairly new to all this so clearly there's something I'm not getting right!
The problem might be in declaration of hideSnackBar function
export const hideSnackBar = () => {
type: SNACKBAR_HIDE
};
Here the function is trying to return an Object Literal from Arrow Function. This will always return undefined. As the parser doesn't interpret the two braces as an object literal, but as a block statement. Thus the error, Cannot read property 'type' of undefined as store is expecting an action with property type.
Replace code like this and see if it works.
export const hideSnackBar = () => ({
type: SNACKBAR_HIDE
});
The parentheses forces it to parse as Object Literal. Hope this helps
I had exported it like
export default userReducer();
and not like this:
export default userReducer;
Just get rid of that ()
Found out that it was case of wrong order in receiving the arguments when using redux-thunk.
// wrong argument order
const anAction = () => (getState, dispatch) => {...}
// correct one
const anAction = () => (dispatch, getState) => {...}
Can you help me with exception Unexpected key "userName" found in preloadedState argument passed to createStore. Expected to find one of the known reducer keys instead: "default". Unexpected keys will be ignored.
I discovered this Link but it doesn't help me. I don't undestand something, maybe this part from documentation: plain object with the same shape as the keys passed to it
Can you exlain me my mistake on my example?
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from 'react-redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import App from './containers/App.jsx';
import * as reducers from './reducers'
import types from './constants/actions';
const reducer = combineReducers(reducers);
const destination = document.querySelector("#container");
var store = createStore(reducer, {
userName : ''
});
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
destination
);
console.log(1)
store.subscribe( ()=> {
console.log("-------------------------")
let s = store.getState()
console.log("STATE = " + s)
for (var k in s) {
if (s.hasOwnProperty(k)) {
console.log("k = " + k + "; value = " + s[k]);
}
}
})
store.dispatch({
type: types.LOAD_USER_NAME,
userName : "Oppps1"
})
my reducer:
import types from './../constants/actions'
export default function userNameReducer (state = {userName : 'N/A'}, action) {
console.log('inside reducer');
switch (action.type) {
case types.LOAD_USER_NAME:
console.log("!!!!!!!!!!!!!!!")
console.log("action.userName = " + action.userName)
for (var k in state) {
if (state.hasOwnProperty(k)) {
console.log("k = " + k + "; value = " + state[k]);
}
}
return action.userName;
default:
return state
}
}
result in console after execution:
TLDR: stop using combineReducers and pass your reducer to createStore directly. Use import reducer from './foo' instead of import * from './foo'.
Example with default import/export, no combineReducers:
// foo.js
function reducer(state, action) { return state; }
export default reducer;
----
// index.js
import myReducer from './foo';
Example with combineReducers
// foo.js
export default (state, action) => { ... }
----
// bar.js
export default (state, action) => { ... }
----
// index.js
import foo from './foo';
import bar from './bar';
const store = createStore(combineReducers({
foo,
bar,
});
The second argument of createStore (preloaded state) must have the same object structure as your combined reducers. combineReducers takes an object, and applies each reducer that is provided in the object to the corresponding state property. Now you are exporting your reducer using export default, which is transpiled to something like module.exports.default = yourReducer. When you import the reducer, you get module.exports, which is equal to {default: yourReducer}. Your preloaded state doesn't have a default property thus redux complains. If you use import reducer from './blabla' you get module.exports.default instead which is equal to your reducer.
Here's more info on how ES6 module system works from MDN.
Reading combineReducers docs from redux may also help.
Or just:
import yesReducer from './yesReducer';
const store = createStore(combineReducers({
yesReducer,
noReducer: (state = {}) => state,
});
import * as reducers from './reducers'
is a good technique to avoid having your core code depend on the various functionalities implementations.
In order to make it work, you have to specify the name of the reducer to be the same as your store key userName. This can be achieved this way:
In the index.js that sits in the reducers folder, do
export { userNameReducer as userName } from "./UserNameReducer"
export { otherReducer as other } from "./OtherReducer"
An other way would be to directly rename the exported reducer the same as the store key.
I want to persist some parts of my state tree to the localStorage. What is the appropriate place to do so? Reducer or action?
Reducer is never an appropriate place to do this because reducers should be pure and have no side effects.
I would recommend just doing it in a subscriber:
store.subscribe(() => {
// persist your state
})
Before creating the store, read those persisted parts:
const persistedState = // ...
const store = createStore(reducer, persistedState)
If you use combineReducers() you’ll notice that reducers that haven’t received the state will “boot up” as normal using their default state argument value. This can be pretty handy.
It is advisable that you debounce your subscriber so you don’t write to localStorage too fast, or you’ll have performance problems.
Finally, you can create a middleware that encapsulates that as an alternative, but I’d start with a subscriber because it’s a simpler solution and does the job well.
To fill in the blanks of Dan Abramov's answer you could use store.subscribe() like this:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
Before creating the store, check localStorage and parse any JSON under your key like this:
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
You then pass this persistedState constant to your createStore method like this:
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
In a word: middleware.
Check out redux-persist. Or write your own.
[UPDATE 18 Dec 2016] Edited to remove mention of two similar projects now inactive or deprecated.
If anybody is having any problem with the above solutions, you can write your own to. Let me show you what I did. Ignore saga middleware things just focus on two things localStorageMiddleware and reHydrateStore method. the localStorageMiddleware pull all the redux state and puts it in local storage and rehydrateStore pull all the applicationState in local storage if present and puts it in redux store
import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga';
import decoristReducers from '../reducers/decorist_reducer'
import sagas from '../sagas/sagas';
const sagaMiddleware = createSagaMiddleware();
/**
* Add all the state in local storage
* #param getState
* #returns {function(*): function(*=)}
*/
const localStorageMiddleware = ({getState}) => { // <--- FOCUS HERE
return (next) => (action) => {
const result = next(action);
localStorage.setItem('applicationState', JSON.stringify(
getState()
));
return result;
};
};
const reHydrateStore = () => { // <-- FOCUS HERE
if (localStorage.getItem('applicationState') !== null) {
return JSON.parse(localStorage.getItem('applicationState')) // re-hydrate the store
}
}
const store = createStore(
decoristReducers,
reHydrateStore(),// <-- FOCUS HERE
applyMiddleware(
sagaMiddleware,
localStorageMiddleware,// <-- FOCUS HERE
)
)
sagaMiddleware.run(sagas);
export default store;
Building on the excellent suggestions and short code excerpts provided in other answers (and Jam Creencia's Medium article), here's a complete solution!
We need a file containing 2 functions that save/load the state to/from local storage:
// FILE: src/common/localStorage/localStorage.js
// Pass in Redux store's state to save it to the user's browser local storage
export const saveState = (state) =>
{
try
{
const serializedState = JSON.stringify(state);
localStorage.setItem('state', serializedState);
}
catch
{
// We'll just ignore write errors
}
};
// Loads the state and returns an object that can be provided as the
// preloadedState parameter of store.js's call to configureStore
export const loadState = () =>
{
try
{
const serializedState = localStorage.getItem('state');
if (serializedState === null)
{
return undefined;
}
return JSON.parse(serializedState);
}
catch (error)
{
return undefined;
}
};
Those functions are imported by store.js where we configure our store:
NOTE: You'll need to add one dependency: npm install lodash.throttle
// FILE: src/app/redux/store.js
import { configureStore, applyMiddleware } from '#reduxjs/toolkit'
import throttle from 'lodash.throttle';
import rootReducer from "./rootReducer";
import middleware from './middleware';
import { saveState, loadState } from 'common/localStorage/localStorage';
// By providing a preloaded state (loaded from local storage), we can persist
// the state across the user's visits to the web app.
//
// READ: https://redux.js.org/recipes/configuring-your-store
const store = configureStore({
reducer: rootReducer,
middleware: middleware,
enhancer: applyMiddleware(...middleware),
preloadedState: loadState()
})
// We'll subscribe to state changes, saving the store's state to the browser's
// local storage. We'll throttle this to prevent excessive work.
store.subscribe(
throttle( () => saveState(store.getState()), 1000)
);
export default store;
The store is imported into index.js so it can be passed into the Provider that wraps App.js:
// FILE: src/index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './app/core/App'
import store from './app/redux/store';
// Provider makes the Redux store available to any nested components
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Note that absolute imports require this change to YourProjectFolder/jsconfig.json - this tells it where to look for files if it can't find them at first. Otherwise, you'll see complaints about attempting to import something from outside of src.
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
I cannot answer #Gardezi but an option based on his code could be:
const rootReducer = combineReducers({
users: authReducer,
});
const localStorageMiddleware = ({ getState }) => {
return next => action => {
const result = next(action);
if ([ ACTIONS.LOGIN ].includes(result.type)) {
localStorage.setItem(appConstants.APP_STATE, JSON.stringify(getState()))
}
return result;
};
};
const reHydrateStore = () => {
const data = localStorage.getItem(appConstants.APP_STATE);
if (data) {
return JSON.parse(data);
}
return undefined;
};
return createStore(
rootReducer,
reHydrateStore(),
applyMiddleware(
thunk,
localStorageMiddleware
)
);
the difference is that we are just saving some actions, you could event use a debounce function to save only the last interaction of your state
If you don't need to copy all redux store to localStorage you can use the specific store arguments:
store.subscribe(()=>{
window.localStorage.setItem('currency', store.getState().lang)
})
And set initial state argument value like:
const initialState = {
currency: window.localStorage.getItem('lang') ?? 'en',
}
In this case, you don't need to pass const persistedState to const store = createStore()
I'm a bit late but I implemented a persistent state according to the examples stated here. If you want to update the state only every X seconds, this approach may help you:
Define a wrapper function
let oldTimeStamp = (Date.now()).valueOf()
const millisecondsBetween = 5000 // Each X milliseconds
function updateLocalStorage(newState)
{
if(((Date.now()).valueOf() - oldTimeStamp) > millisecondsBetween)
{
saveStateToLocalStorage(newState)
oldTimeStamp = (Date.now()).valueOf()
console.log("Updated!")
}
}
Call a wrapper function in your subscriber
store.subscribe((state) =>
{
updateLocalStorage(store.getState())
});
In this example, the state is updated at most each 5 seconds, regardless how often an update is triggered.
I was looking badly for an entire example on how to persist state into a local storage using redux-toolkit-persist with no success until I came across #canProm response above to solve my issue.
This is what is working for me
//package.json
"reduxjs-toolkit-persist": "^7.0.1",
"lodash": "^4.17.21"
//localstorage.ts
import localStorage from 'reduxjs-toolkit-persist/es/storage';
export const saveState = (state: any) => {
try {
console.log(state);
const serializableState = JSON.stringify(state);
localStorage.setItem('globalState', serializableState);
} catch (err) {
console.log('Redux was not able to persist the state into the localstorage');
}
};
export const loadState = () => {
try {
const serializableState: string | any =
localStorage.getItem('globalState');
return serializableState !== null || serializableState === undefined ? JSON.parse(serializableState) : undefined;
} catch (error) {
return undefined;
}
};
//slices - actions
//reduxjs-toolkit-slices.ts
import { combineReducers, createSlice, PayloadAction } from '#reduxjs/toolkit';
import { UserModel } from '../model/usermodel';
import { GlobalState } from './type';
const deaultState: GlobalState = {
counter: 0,
isLoggedIn: false
};
const stateSlice = createSlice({
name: "state",
initialState: deaultState,
reducers: {
isLoggedIn: (state, action: PayloadAction<boolean>) => {
console.log('isLogged');
console.log(state.isLoggedIn);
console.log(action);
state.isLoggedIn = action.payload;
console.log(state.isLoggedIn);
},
setUserDetails: (state, action: PayloadAction<UserModel>) => {
console.log('setUserDetails');
console.log(state);
console.log(action);
//state.userContext.user = action.payload;
}
}
});
//export actions under slices
export const {
isLoggedIn: isUserLoggedAction,
setUserDetails: setUserDetailActions
} = stateSlice.actions;
//TODO: use the optimal way for combining reducer using const
//combine reducer from all slice
export const combineReducer = combineReducers({
stateReducer: stateSlice.reducer
});
//storeConfig
//reduxjs-toolkit-store.ts
import { configureStore } from '#reduxjs/toolkit';
import { throttle } from 'lodash';
import { persistReducer } from 'reduxjs-toolkit-persist';
import autoMergeLevel2 from 'reduxjs-toolkit-persist/lib/stateReconciler/autoMergeLevel2';
import storage from 'reduxjs-toolkit-persist/lib/storage';
import { loadState, saveState } from './localStorage';
import { combineReducer } from './reduxjs-toolkit-slices';
// persist config
const persistConfig = {
key: 'root',
storage: storage,
stateReconciler: autoMergeLevel2,
};
const persistedReducer = persistReducer(persistConfig, combineReducer);
// export reducers under slices
const store = configureStore({
reducer: persistedReducer,
devTools: process.env.NODE_ENV !== 'production',
preloadedState: loadState(), //call loadstate method to initiate store from localstorage
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: true,
serializableCheck: false,
}),
});
// handle state update event. Whenever the state will change, this subscriber will call the saveState methode to update and persist the state into the store
store.subscribe(throttle(() => {
saveState(store.getState());
}, 1000));
export default store;
//App.ts
import { persistStore } from 'reduxjs-toolkit-persist';
import { PersistGate } from 'reduxjs-toolkit-persist/integration/react';
import './i18n';
let persistor = persistStore(store);
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={<div>Loading .....</div>} persistor={persistor}>
<HalocarburesRouter />
</PersistGate>
</Provider>,
document.getElementById('ingenierieMdn'));