Clarification on Stores in Reactjs-Redux - reactjs

I am currently learning how to use Redux in my ReactJS application and all the tutorials I've seen lead me to believe that there can only be one store in Redux. In a real-world applications, you may have multiple streams of data coming from a REST api or some other source. So, for example, I may be looking at a list of customers in one component and a list of projects in another and list of users in yet another. My question is: Does Redux allow you to create a store for each entity with it's own reducer and actions? For example, a customer store, a project store and user store? If not how would one organize this in a single store without everything getting convoluted? Thanks.
* EDIT *
So my state would look something like:
let initalState={
customers:{
data:[]
...
},
projects:{
data:[]
...
}
users:{
data:[]
...
}
}

I think that combinereducers is what you are looking for.
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.
Imagine you want to manage the customers, projects and users.
You will get one reducer per feature :
const customersInitialState = {data:[], ...}
export default function customersReducer(state = customersInitialState , action) {
switch (action.type) {
case 'ADD':
return {...state, data: [...state.data, action.payload]}
default:
return state
}
}
Then you will combine all theses reducers into a single one
export default combineReducers({
customers: customersReducer,
projects: projectsReducer,
users: usersReducer
})
const store = createStore(reducer)
Finally the state of your store will be like this :
{
customers: {data: [], ...},
projects: {data: [], ...},
users: {data: [], ...},
}

Related

How do you implement multiple tabs for a Redux slice that's associated with a component?

https://redux.js.org/tutorials/essentials/part-2-app-structure#redux-slices
How do you implement multiple tabs for a Redux slice that's associated with a component? I have a component that's associated to 1 Redux slice, but now I need to refactor the whole code to insure that each tab of that component is associated with its own slice. So instead of a 1 to 1 relationship, we have a many to many relationship where each tab has its own unique slice. How do you implement it without changing the redux reducers?
One way of doing this is to copy and paste the slice and create slices called editor_1, editor_2, editor_3, etc. and duplicate every action and reducer x number of times, but that's terrible, but the other method requires a lot of breaking changes and is a lot more difficult.
https://codesandbox.io/s/react-redux-todo-list-bnv8y?from-embed=&file=/src/redux/reducers/todos.js
A simple example would be a todo redux store and having to duplicate 10 todo stores on each tab, each tab having its own "store" or "slice" that are independent of one another. What's the best way to go about solving this issue?
You don't need any duplication in your code. Instead use a higher order reducer and a dynamic state shape like:
{
[k: NameSpace]: ITabState;
}
Then create your reducer to select the correct namespace
// Higher level reducer for namespacing
export const MultiReducer = (state = {}, action) => {
if (!action.payload || !action.payload.namespace) {
return state; // Probably something is wrong
}
switch (action.type) {
// Stuff to handle
case actionTypeKeys.DO_A_THING:
return {
...state,
[action.payload.namespace]: {
...singleReducer(state[action.payload.namespace], action),
},
};
default:
return state;
}
};
Edit:
Your state would be something like
{
tab1: { todos: [] },
tab2: { todos: [] },
tab3: { todos: [] },
}

Is this correct way to deep clone array of objects as property inside object?

I have this reducer.
const userInitialState = {
users: [],
};
const users = (state = userInitialState, action) => {
if (action.type === "FETCH_USERS") {
return {
...state,
users: action.payload,
};
}
return state;
};
export default combineReducers({
users,
});
initially the users property is edmpty array,when the new results from the api call comes
for example response like
https://jsonplaceholder.typicode.com/users
is this the correct way for immutable way in redux store for my array inside ?
A proper immutable update is best described as "a nested shallow clone". You don't want to copy every value in a nested data structure - just the ones that need to be updated.
But yes, that looks correct.
A couple additional observations:
You should read through the post The Complete Guide to Immutability in React and Redux and the Redux docs page on Immutable Update Patterns to better understand how to do immutable updates correctly
But, you should really be using our official Redux Toolkit package, which uses Immer to let you write "mutating" update logic that is turned into safe and correct immutable updates.

Should every React component have it's own slice, when using createEntityAdapter?

I'm using Redux-tookit's createSlice and createEntityAdapter with normalized data.
This is a typical blog app with (posts, comments, users) - Entities
Usually, before using createEntityAdapter I would:
Fetch, normalize and store data in postsSlice
So my postSlice state would look something like this:
blogPosts: {entities: {posts: {}, users:{}, comments: {}}, ids:[]}
Get id's from postsSlice's state to Posts component
Pass comment/user id's from Posts down to children - Comment User components, where they would get data using passed id's with selectors connected to parent's postSlice state
const postsAdapter = createEntityAdapter();
const postsSlice = createSlice({
name: "posts",
initialState: postsAdapter.getInitialState(),
reducers: {
setPosts: (state, { payload }) =>
postsAdapter.setAll(state, payload.entities.posts),
},
});
The problem is:
When using createEntityAdapter
Since we're using createEntityAdapter.getInitialState() we get the same initialState {entities: {} ids: []} pattern in every slice.
And this doesn't allow to have initialState like I had before:
blogPosts: {entities: {posts: {}, users:{}, comments: {}}, ids:[]}
Should every component (Posts, User, Comment) have it's own slice/reducer and fetch it's own piece of data with thunk from the same endpoint?
So that: (according the createEntityAdapter.getInitialState() pattern)
postSlice state would just contain post Entity - entities: {posts: {}, ids:[]}
commentSlice state - comments Entity - entities: {comments: {}, ids:[]}
etc...
No. There has never been a 1:1 association between components and Redux state structure. Instead, you should organize your state in terms of your data types and update logic, and components should access and re-shape that data for their own needs as necessary.
Note that there are multiple ways to approach structuring that data in the store even if it's being normalized. For example, you could have each data type as its own top-level slice, or have a shared entities reducer with each of those types nested inside.

Different instances of store

guys.
I make project where we have tabs, like the browsers have. Each tab contains user searches with different settings and results of these searches. I can not find out the correct way to store this data.
I think, I need kind of several stores. Because I have only tabs which switch users between a kind of different applications, but inside one. In other case, I need to store data twice - remembering the current state, and collect old searches in some 'history' reducer.
Sorry, it is my first experience here, please help with it if anybody can.
You can create multiple data classes that contain variables and their values. These data classes can then be combined and used when creating the store.
This method allows you to have multiple sections in your store and each of your components can subscribe to the sections that they need. The Component will have the data of these sections he subscribed to and will re-render when one of these sections is updated.
Example of data classes:
pageData.js
export const pageData = {
pageNumber: 1,
pageSize: 30,
};
userData.js
export const userData = {
language: 'English',
timezone: 'ESTERN',
};
These classes are then combined when creating the store:
store.js
import pageData from .../pageData;
import userData from .../userData;
const defaultState = {
pageData,
userData,
};
export const store = createStore(rootReducer, defaultState));
Your reducer that needs to modify pageData will need to have the name pageData as well. Same thing for the userData.
After all this has been set up, you'll have to mapStateToProps() your components to the data you want them to subscribe to.
For example, if you want your PageComponent.js to only know the pageData, then in that component, you will use the method:
function mapStateToProps (state) {
return {
pageData: state.pageData
};
}
I would recommend looking into the redux documentation to learn how to setup mapStateToProps().
When all of this is done, you can console.log(this.props) and see that your data sections are there and well separated.

Combine Reducers without their functional keys

I have been working on a React / Redux Application, where now the reducer for single feature has become big enough for the thought of dividing the reducer further.
So I was thinking is there a way to divide the reducer into two different reducers and combining them without adding keys of their functional names.
For Ex:
const nowShowing = function(state = {}, action){
switch(action.type){
case types.NS_MOVIES:
return Object.assign({}, state, { nowShowingMovies: action.data })
}
const comingSoon = function(state = {}, action){
switch(action.type){
case types.CS_MOVIES:
return Object.assign({}, state, { comingSoonMovies: action.data })
}
I am looking to check if its possible to combine these reducers
const movies = combineReducers({
nowShowing,
comingSoon
})
in such a way that i can access them in the following manner
mapStateToProps(state){
nowShowing: state.movies.nowShowing,
comingSoon: state.movies.comingSoon
}
The reason i am looking for a solution like this is because, it will allow my entire application to work as earlier, but the nowShowing & comingSoon reducer become separate and my code becomes more modular.
I did try returning an object instead of combining the reducer using the combineReducers function. But that causes the entire state of the reducer to reset when there is a change in value as it recreates the object.
I think this kind of solution is not possible or it should not be attempted. But I would to understand more why, as I do agree that this points to more over architectural flaw in constructing the reducers in the first place.
Any help would be highly appreciated.
Thanks

Resources