Not able to access store on non react component - reactjs

The redux getState method is not available. Do I need any middleware for achieving the desired result. Following is the code
const configureStore = (initialState = {}) => {
return createStore(
rootReducer,
initialState,
applyMiddleware(...middleware),
);
};
export default configureStore;
util.js
import store from '../../store';
store.getState()
// _store2.default.getState is not a function

You are returning a function instead of your store. Seems like you have mixed up reducers with the store. What you want is this:
const store = createStore(
rootReducer,
initialState,
applyMiddleware(...middleware),
);
export default store;

Looks like you intended to, at some point, initialize the store.
I'm not sure how you want to layout your app, but
// index.js
import configureStore from 'store';
export const store = configureStore({ ... someInitialState });
then
// util.js
import store from 'index';
// use store
I don't think this is the best solution - instead of exporting an store initializer from store, just initialize the store and export the store.

Related

redux-undo that wraps all slices in RTK?

I am implementing redux-undo library introduced in redux docs in my RTK project. The example in the docs guides you to wrap single slice (or reducer) to make it 'undoable'.
// todos.js
import undoable from 'redux-undo'
/* ... */
const todos = (state = [], action) => {
/* ... */
}
const undoableTodos = undoable(todos)
export default undoableTodos
import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'
const todoApp = combineReducers({
todos,
visibilityFilter
})
export default todoApp
You may wrap one or more reducers in undoable at any level of the reducer composition hierarchy. We choose to wrap todos instead of the top-level combined reducer so that changes to visibilityFilter are not reflected in the undo history.
This example, as described above, only restores changes in todos slice. Anything happened to visibilityFilter is not undoable.
What I want is to wrap the entire store with undoable() so that with one undo() function call, you can revoke all changes to the store.
Below is my attempt in redux toolkit and I want to know if this is the right way to go.
import { configureStore } from "#reduxjs/toolkit";
import undoable from 'redux-undo'
import todoSlice from "../features/todo/todoSlice";
import visibilityFilterSlice from "../features/visibilityFilter/visibilityFilterSlice";
const store = configureStore({
reducer: {
todos: todoSlice,
visibilityFilter: visibilityFilterSlice,
},
});
export default undoable(store);
No, your attempt wraps the store instance, not a reducer - redux-undo won't know what to make of that. Try this instead (using combineReducers with RTK is totally fine):
const rootReducer = combineReducers({
todos: todoSliceReducer,
visibilityFilter: visibilityFilterSliceReducer,
})
const undoableRootReducer = undoable(rootReducer)
const store = configureStore({
reducer: undoableRootReducer,
});
For TypeScript it is important not to do reducer: undoable(rootReducer),, but to do this in a variable declaration above the configureStore call.

How to get middlewares from getDefaultMiddleware without deprecation message

I'm using a different setup for initializing the redux store (I don't want to use the configureStore method from redux-toolkit) for the purpose of injecting reducers on runtime.
import {
createStore,
combineReducers,
applyMiddleware,
createImmutableStateInvariantMiddleware,
} from "#reduxjs/toolkit";
import { composeWithDevTools } from "#redux-devtools/extension";
import { createCustomMiddleWare} from "./myCustomMiddleWare";
const staticReducers = {};
const middlewares = [
createImmutableStateInvariantMiddleware(),
createCustomMiddleWare(),
];
const createReducer = (asyncReducers = {}) =>
combineReducers({
...staticReducers,
...asyncReducers,
});
export const initializeStore = (initializeState = {}) => {
const store = createStore(
createReducer(),
initializeState,
composeWithDevTools(applyMiddleware(...middlewares))
);
store.asyncReducers = {};
store.injectReducer = (key, reducer) => {
store.asyncReducers[key] = reducer;
store.replaceReducer(createReducer(store.asyncReducers));
return store;
};
return store;
};
export default initializeStore;
I was wondering wether there is a way to add Thunk middleware from redux-toolkit (without installing the redux-thunk package seperately)
I tried using the getDefaultMiddleware() method from redux-toolkit which imports three default middlewares that ships with redux-toolkit including thunk, but since I'm not using it as paramether for the configureStore's middleware callback, I get this error that getDefaultMiddleware is deprecated.
I was able to import one of the default middlewares by using createImmutableStateInvariantMiddleware() function that I found in the official documentations but I could not find a way to import thunk or serlizied middlewares (two other default middlewares of redux-toolkit)
The answer would be to use configureStore and using the middleware callback option.
There is really no good reason that would be using createStore here, that could come down to
const store = configureStore({
reducer: createReducer(),
preloadedState: initializeState,
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(createCustomMiddleWare())
})

kepler.gl state doesnt exist. You might forget to mount keplerGlReducer in your root reducer

I try to integrate kepler.gl into react-boilerplate.
I Mount kepler.gl reducer in the app reducer like this
export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
keplerGl: keplerGlReducer, // mount kepler.gl reducer
global: globalReducer,
language: languageProviderReducer,
...injectedReducers,
});
// Wrap the root reducer and return a new root reducer with router state
const mergeWithRouterState = connectRouter(history);
return mergeWithRouterState(rootReducer);
}
and in the create store part, I have
const middlewares = [
sagaMiddleware,
taskMiddleware,
routerMiddleware(history),
];
const enhancers = [applyMiddleware(...middlewares)];
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers),
);
When I run the app, I get red text from console complaining
kepler.gl state doesnt exist. You might forget to mount
keplerGlReducer in your root reducer.If it is not mounted as
state.keplerGl by default, you need to provide getState as a prop
and the map is not displayed in the page, but I can see the keplerGl state from redux DevTools like this.
Could you suggest how to fix this issue? Thank you!
This is my code and it works.
I think that you have forgotten add enhanceReduxMiddleware;
I hope this help you.
reducer.js
// KEPLER.GL
import keplerGlReducer from "kepler.gl/reducers";
/**
* Creates the main reducer with the dynamically injected ones
*/
const createReducer = injectedReducers => {
return combineReducers({
global: globalReducer,
language: languageProviderReducer,
keplerGl: keplerGlReducer,
...injectedReducers,
});
};
export default createReducer;
configureStore.js
import { enhanceReduxMiddleware } from 'kepler.gl/middleware';
export default function configureStore(initialState = {}, history) {
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middlewares = enhanceReduxMiddleware([thunk]);
const enhancers = [applyMiddleware(...middlewares)];
const store = createStore(
createReducer(),
initialState,
composeEnhancers(...enhancers)
);
return store;
};

Dispatching `push` does not change route in React Redux Router

I'm working on a project with the React Redux Router, and am trying to change the page. When a component dispatches a "push" action, I see the "##router/LOCATION_CHANGE" come through, but nothing changes.
I do have the routerMiddleware applied as well,
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory'
import rootReducer from '../reducers';
export const history = createHistory();
const middleware = routerMiddleware(history)
export function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk),
applyMiddleware(middleware)
);
}
any thoughts as to what I'm doing incorrectly?
applyMiddleware expects a list of middlewares, so you're using it wrong:
Please change it to:
export const history = createHistory();
const middleware = routerMiddleware(history)
export function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk,middleware)
);
}
This also explains why switching them worked (the store received another middleware).

react redux store is not a function

const rootReducer = combineReducers({
router: routerStateReducer,
todos,
})
const createStoreWithMiddleware = compose(
applyMiddleware(thunk),
reduxReactRouter({ routes, createHistory })
)(createStore)(reducer);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(rootReducer, initialState)
It is giving me createStoreWithMiddleware is not a function.. Why this ?
You're executing the result of compose (which returns a function). So instead of setting createStoreWithMiddleware to the returned function, you are setting it to the executed result with the variable reducer.
Not sure what the variable reducer in this context is since you have rootReducer defined above. Your code should probably read:
const createStoreWithMiddleware = compose(
applyMiddleware(thunk),
reduxReactRouter({ routes, createHistory })
)(createStore)
doing so will define createStoreWithMiddleware as an extended createStore function, which can then receive your rootReducer and initialState.

Resources