import { configureStore } from "#reduxjs/toolkit";
import testSlice from "./testSlice";
import {combineReducers} from "redux";
const rootReducer = combineReducers({test: testSlice})
export const store = configureStore({
reducer: rootReducer,
});
export type RootState = ReturnType<typeof rootReducer>
This is my current workaround in order to get the type of my root reducer. I'm reading the docs and I can't seem to find how to get my root reducer from the store if I was using slices to create the reducer in my configure store. It's just disappointing that I have to use combineReducers again while using redux-toolkit just to get my rootReducer type.
I'm looking for a code like this:
import { configureStore } from "#reduxjs/toolkit";
import testSlice from "./testSlice";
import userSlice from "./userSlice";
export const store = configureStore({
reducer: {test: testSlice, user: userSlice},
});
export type RootState = ReturnType<typeof store.getReducer()>
A better type for RootState would be as below:
export type RootState = ReturnType<typeof store.getState>
This implementation is included in the document. Please take time to read it.
If your intention of getting the rootReducer isn't only for defining the RootState type, you can simply named-export it from store file and then import it in your desired file to use.
// store.js
// ...
export const rootReducer = combineReducers({test: testSlice});
It's not a common and practical usage for the rootReducer to be imported and consumed in other places but the store file, where it will be used to configure the store object.
Therefore, I think there's no point for Redux Toolkit to provide a way to access the rootReducer.
You don't need to
Huan's answer is spot-on. It is very unlikely that you will actually need to access the root reducer type. You can get the state type without it. Their answer is the best solution to underlying problem.
But if you want to...
If anyone reading this question would like to know how to derive the root reducer type from the store type, it can be done by using TypeScript conditional types. This is the same sort of logic that you see in the redux source code.
We can define a reusable utility type that gets the reducer type from the type of the store. It does this by accessing the types for the state S and the action A, which are both generic type parameters of the redux Store<S, A> type. Then we apply those same generics to the Reducer<S, A> type.
// Can be imported from 'redux' or from '#reduxjs/toolkit', both are the same.
import { Reducer, Store } from '#reduxjs/toolkit';
type ReducerFromStore<T> = T extends Store<infer S, infer A> ? Reducer<S, A> : never
You can use this utility type to get the root reducer type from a specific store instance.
export const store = configureStore({
reducer: {test: testSlice, user: userSlice},
});
export type RootReducer = ReducerFromStore<typeof store>;
Note: The exact type of the store object created by configureStore is the redux toolkit EnhancedStore type. But this extends the core redux Store type, so no special handling is needed.
Related
import { configureStore } from "#reduxjs/toolkit";
import testSlice from "./testSlice";
import {combineReducers} from "redux";
const rootReducer = combineReducers({test: testSlice})
export const store = configureStore({
reducer: rootReducer,
});
Which one is better? for performance and use purpose. Which is good to use?
They are totally different things.
The reducer option is an object of slice reducers, like {users : usersReducer, posts : postsReducer}, configureStore will automatically create the root reducer by passing this object to the Redux combineReducers utility. See here
RTK configureStore setup the redux store configuration, not only reducer, but also middlewares, dev tools, preloaded state, and enhancers.
The Redux combineReducers helper function turns an object whose values are different reducing functions into a single reducing function
I am learning React-Redux and TypeScript.
In my small app I want to use localStorage to save data locally.
I tried to solve it according to this answer, but encountered a typescript error. I tried to define type any as a temporary solution, but it didn't help.
Argument of type 'string | null' is not assignable to parameter of type 'string'.
Type 'null' is not assignable to type 'string'
Since there are 2 actions, reducers, I had to use combineReducers. For side effects I am using thunk middleware.
I assume store is the correct component to save data.
Any help is appreciated
rootReducer.ts
import { combineReducers } from 'redux'
import carReducer from './Car/CarReducer'
import ProductReducer from "./Products/ProductReducer"
const rootReducer = combineReducers({
car: carReducer,
products: ProductReducer
})
export default rootReducer
store.ts
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import RootReducer from './RootReducer'
const persistedState = localStorage.getItem('state') ?
JSON.parse(localStorage.getItem('state')) : {} // <--- typescript error here
const store = createStore(
RootReducer,
persistedState,
composeWithDevTools(applyMiddleware(thunk))
)
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
export default store
Typescript doesn't have a way to know that calling getItem multiple times is going to result in the same thing being returned each time. So while you do check for null with the first value that's returned, this makes no difference to the second value.
The fix is to just call it once, and save the result to a variable:
const temp = localStorage.getItem('state');
const persistedState = temp ? JSON.parse(temp) : {};
I have a configured project with React, Redux, Immutable.js + TypeScript. During implementation I was trying to declare types as much as possible and found interesting issue. See code example below:
Short configuration of redux store
import { createStore } from 'redux';
import { combineReducers } from 'redux-immutable';
const rootReducer = combineReducers({...});
const store = createStore(rootReducer);
Somewhere inside component
// ...
const mapStateToProps = (state: ReturnType<typeof rootReducer>) => {
// state is plain object :(
};
On state hover in VS Code, tooltip shows that state is a plain object, however it is not. It should be a custom collection from Immutable.js
How can I get a correct type of rootReducer? Or what I am doing wrong?
Screenshots:
P.S. StateType and ReturnType do the same stuff
I spent a lot of time on finding a solution of how to make TypeScript work with Immutable.js in pair and unfortunately there is no explicit/trivial solution (or I didn't find it).
If you on the start of your project and looking for some alternatives I would highly recommend you to take a look at the Immer library. It provides mostly the same functionality and perfectly supports TypeScript typings.
This works (no need for Immutable.js):
export type RootState = ReturnType<typeof rootReducer>;
If for some reason it does not works, this one should work:
export type RootState = ReturnType<typeof store.getState>
I am using flux. I have used combineReducers - all works. But what is the purpose of using combineReducers in the redux?
any one help me to understand by updating my code?
why should I combine Reducers ?
if I am not use, what is the impact ?
here is my code :
import { combineReducers } from "redux";
import rootReducer from "./countAddReducer";
export default combineReducers({
value: rootReducer
});
Live Demo with sample app
combineReducers is used to combine all the reducers to one single store object, so that it can be used in every component.
In flux, you would have different Flux Stores to manage different state. With Redux, there is just one store, but combineReducers helps you keep the same logical division between reducers.
In your example,
export default combineReducers({
value: rootReducer,
removes: countRemoveReducer
});
you got two reducers rootReducer and countRemoveReducer, and you combine these two make available in the components connect() method as mapStateToProps, where mapStateToProps have a state object which contains both these reducers.
Now, if you want to share state between two reducers then we cannot achieve it with combineReducers. For that purpose we need redux-thunk.
I have updated your code, https://codesandbox.io/s/lq87v947
It separates the state corresponding to a particular reducer into their own object.
Example:
import { combineReducers } from "redux";
import userReducer from "./userReducer";
import blogPost from "./blogReducer";
export default combineReducers({
user: userReducer,
blogPost: blogReducer,
});
When you start dispatching actions to either userReducer or blogReducer, the global redux state is just one object, but that object looks like this.
const reduxState = {
user: {
//state created by userReducer will go in here
},
blogPost: {
//state created by blogReducer will go in here
}
}
I'm having issues with creating my store using redux. I have a feeling it is how my createStore is passing in the middleware.
The line return createStore(rootReducer, applyMiddleware(thunk), initialState)' is giving me the warning Argument Type GenericStoreEnhancer is not assignable to parameter type StoreEnhancer
What does that mean?
I believe I'm following the documentation here correctly, so I'm at a loss.
I know my store is not being created/exported correctly because I'm getting an undefined for my state.
Any ideas how to create the store correctly?
Thanks,
Here is my configureStore.js file:
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';
export default function configureStore(initialState) {
return createStore(rootReducer, applyMiddleware(thunk), initialState);
}
You should specify your initial state in each reducer and not by createStore.
For example,
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
docs:
https://github.com/gaearon/redux-thunk
return createStore(rootReducer, applyMiddleware(thunk), initialState)' is giving me the warning Argument Type GenericStoreEnhancer is not assignable to parameter type StoreEnhancer
Its because ,you are passing parameter in wrong order to creatStore
The right signature is,
createStore(reducer, [preloadedState], [enhancer])
Please refer redux-docs
So,it should be like this.
createStore(rootReducer, initialState, applyMiddleware(thunk))