Options for dynamically adding reducers within a package being consumed - reactjs

I have 2 node packages A and B with A consuming B. I have the store being defined using createStore and combineReducers in A. This just has the reducers in A.
I want to add a new reducer in package B. What are my options to connect it to the store? I've been looking at redux-injector. The other thing I am thinking of is to move reducer from package B to A but that would mean that B would have to consume A and will create a cycle.
Are there any better ways of handling this?

According to your requirement
A-->
store.jsx
B-->
reducer1.js
reducer2.js
So in store.jsx you will import reducers from package B
as
import reducer1 from "../B/reducer1";
import reducer2 from "../B/reducer2";
const rootReducer = combineReducers({
reducer1,
reducer12,
});
export const configureStore = (initialState) => {
//your other store configuration
};
If you want to add any more reducer in package B simply import and add it to store.jsx file.
Where store.jsx is your store configuration.

Related

what is the difference between Redux CombineReducers and Redux-toolkit ConfigureStore

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

Getting the root reducer from configureStore redux toolkit

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.

Store setup with simpleWebRTC

I'm trying to integrate simpreWebRTC to my React-Redux project, but the library has their own redux store and the documentation says this:
"The provided createStore function makes a basic Redux
store useful for getting things started. If you want to
make your own, import reducer from '#andyet/simplewebrtc' and
be sure to assign it to simplewebrtc in the top level of
your state object."
I've tried several approaches but nothing works, any idea? what I'm missing here?
Thanks
This is the code that I have so far:
store.js
import {createStore, applyMiddleware} from 'redux'
import rootReducer from './reducers/index'
import thunk from 'redux-thunk';
export default createStore(rootReducer, applyMiddleware(thunk));
const store = createStore(rootReducer);
console.log(store.getState());
./reducers/index.js
import {combineReducers} from 'redux'
import {reducer as simplewertc} from '#andyet/simplewebrtc'
import liveRoomReducer from './liveRoomReducer'
export default combineReducers({simplewertc, liveRoomReducer});
./reducers/liveRoomReducer.js
const initialState = {
test : 'test'
};
export default function liveRoomReducer(state=initialState, action) {
return state;
};
I'm logging the store state in the console and is showing simplewebrtc on it:
And still showing this error:
Creating your own store with thunk middleware and using combineReducers should do the trick:
import {combineReducers} from 'redux';
import {reducer as simplewebrtc} from '#andyet/simplewebrtc';
import reducer1 from 'path/to/your/reducer1';
import reducer2 from 'path/to/your/reducer2';
export default combineReducers({simplewebrtc, reducer1 , reducer2});
If that isn't working for you please provide what error is showing up if any and some example code of how you create your redux store and root reducer.
Edit: After seeing the updated question with code, we found the problem was in a typo when importing the reducer.

`combineReducers` - not able to understand of requirement and usage

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
}
}

Shall we use multiple combine reducers?

I have three reducers
Home
Listing
Detail
I have one combine reducer for above three. But I want to divide project structure into multiple reducers. Is it a good practice to have multiple combine reducer in the project?
Yes, you can have multiple combineReducers in your App, You can at the top level combine reducers Home , Listing and Detail and even split each individual reducers into multiple and combine them into one.
According to the Redux docs:
You may call combineReducers at any level of the reducer hierarchy.
It doesn't have to happen at the top. In fact you may use it again to
split the child reducers that get too complicated into independent
grandchildren, and so on.
Some more description about combineReducer:
As your app grows more complex, you'll want to split your reducing
function into separate functions, each managing independent parts of
the state.
The combineReducers helper function turns an object whose values are
different reducing functions into a single reducing function you can
pass to createStore.
The resulting reducer calls every child reducer, and gathers their
results into a single state object. The shape of the state object
matches the keys of the passed reducers.
Yes, you can combine multi reducer and use it as one store,
Firstly, you should import all reducers in a new file. then, combine all reducers with combine-reducer technics,like this:
import { combineReducers } from 'redux';
import {Home,Listing,Detail} from '*/**';
const rootReducer = combineReducers({
Home,
Listing,
Detail
})
export default rootReducer
Secondly, import the new file in Store file and create your store with combined-reducer
import { createStore } from 'redux'
import rootReducer from '*/combinestores'
const store = createStore(rootReducer)
console.log(store.getState())optinal
export default store
In the end, in your container you can use your store like this :
(but before it, you should be sure send store as props to Containers)
const mapStateToProps = state => {
return{
*name of your var* : state.Home.*,
*name of your var* : state.Detail.* /*then you can use this var as props anywhere you need*/
}
}
const mapDispatchToProps = dispatch => {
return{
*name of your var* : () => dispatch ( *name of your func*()),
*name of your var* : () => dispatch ( *name of your func*())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(name of func);

Resources