I have a react native app that uses many screens to manage the data in a large object.
For example, each of the following is a screen to manage a portion of 1 object in this app: address, contacts, images, notes, and a few more.
Is there any issue that would conflict with best practices or performance to use a single reducer which passes back the entire object in state?
or should my reduces and state be more screen oriented, passing back only the properties of the object that each screen is handling?
Straight forward answer. It depends
Depends on the data stored by each reducer.(state maintained by each)
If it's complex data better to create a separate reducer.
If each screen's state is just a flat JSON object, keep all of them in single reducer.
At the end combineReducers() will make them all available for us at any place we want by simple connect() method of redux.
Generally we'll maintain a reducer for container where container holds the components which are hydrated by reducer of this container.
It's not an issue even if we maintain a 'reducer' for each component.
And one more good practice is to keep related state say:
cart => cartReducer which in turn accepts all actions on the state of cart like ADD_TO_CART, RESET_CART, CHECKOUT_CART, DELETE_ITEM etc.
And in your case if address, contacts, images etc are related to a single entity, better to maintain a single reducer.
Related
I'm pretty new to Redux and would like to use it my application but I'm stuck at architecture/design phase for the Redux part. Here are my requirements and my suppositions regarding the design.
Application details:
SPA with AngularJS. Other libs used ng-redux, reselect, rxjs.
Component details:
Re-usable grid component to render huge amounts of data.
My idea:
Create a plug-n-play kind of component-based architecture, where all the internal components of the grid are independent of the parent/composing component like search, sort, row, header, cell.
All the components will have their own set of reducer, action, selector, and slice of state from the store.
Because all the components have their own reducers and can be plugged-in on demand, I need them to be lazily registered to the store instead of being accumulated in one place.
Some of the components like search, sort along with having their own state, also can affect other components state. Ex: setting up of query parameters (searchText, sortOrder etc.) to fetch the grid data which would be handled by another component(s).
My thoughts:
For the 1st point, I'm looking into reselect for supplying the dependent slice of state.
For the 2nd point, I'm still confused about which to use combineReducers/replaceReducer for the lazy registration. I feel combineReducers will not fit if I want access to multiple parts of the state.
For the 3rd point, I'm thinking of following approaches:
a. Passing entire state via getState() wherever required to update multiple parts of the state. Though this approach gives me feeling of improper use of Redux.
b. Component A fires its own action which updates their part of the state, then another action is fired for the other component B to update its slice of state. This approach as well feels like breaking the whole idea of Redux, the concept of side-effect could be used here though I don't know how to use it, maybe redux-saga, redux-thunk etc.
NOTE: Use of either of the approaches shouldn't lead to the component knowing about the other components hence whatever has to be done will be done by passing a generic config object like { actionsToFire: ['UPDATE_B'] }.
I need state management while navigating back and forth between the pages of the application, but I don't require hot-reloading, action-replay, or pre-fetching application state from server-side.
Components will also be responsible to destroy their state when no longer required. And state will have a normalized structure.
I know the requirements might seem weird or not-seen-often but I would keep them that way.
Few things I already know are:
I don't need to use Redux like the classic article from Dan says, but I think I need it here in this case.
I know about the Smart and Dumb components, mostly my components might seem smart (i.e aware of application state) but that is how I want to keep them, I might be wrong.
Diagram of the grid component:
Grid Component Diagram
Redux's global store makes encapsulation and dynamic plug-and-play behavior more difficult, but it is possible. There's actually many existing libraries for per-component-instance state and dynamic registration of reducers. (That said, the libraries I've seen thus far for component management are React libraries - you'd have to study some of those and reimplement things yourself for use with Angular.)
I have watched a few videos about reducers, and they all claimed that I should use only one reducer and state for my whole project and I should combine every reducer into one big reducer.
Now my question is, why would I do this? Imagine I have a big application and I combine all reducers. My combined reducer would be huge and a single state change would take quite long since we need to check every single reducer slice.
Should I really just use one reducer for a bigger project? Why should we combine them, instead of creating multiple stores, and what about the performance?
As your app grows more complex, you'll want to split your reducing
function into separate functions, each managing independent parts of
the state.
.combineReducers(...)
Thanks a lot.
Per the Redux FAQ entry on the performance of "calling all reducers":
It's important to note that a Redux store really only has a single reducer function. The store passes the current state and dispatched action to that one reducer function, and lets the reducer handle things appropriately.
Trying to handle every possible action in a single function does not scale well, simply in terms of function size and readability, so it makes sense to split the actual work into separate functions that can be called by the top-level reducer.
However, even if you happen to have many different reducer functions composed together, and even with deeply nested state, reducer speed is unlikely to be a problem. JavaScript engines are capable of running a very large number of function calls per second, and most of your reducers are probably just using a switch statement and returning the existing state by default in response to most actions.
Also, from the FAQ entry on whether you should create multiple stores:
It is possible to create multiple distinct Redux stores in a page, but the intended pattern is to have only a single store. Having a single store enables using the Redux DevTools, makes persisting and rehydrating data simpler, and simplifies the subscription logic.
However, creating new stores shouldn't be your first instinct, especially if you come from a Flux background. Try reducer composition first, and only use multiple stores if it doesn't solve your problem.
As a Redux beginner, given (the idea of) a somewhat larger application I imagine a root reducer similar to:
const rootReducer = combineReducers({ accounting, crm, sales })
Application state in this case would contain accounting, crm, and sales even if the user is only using one part of the application. This may be advantageous, for example as a cache when switching back and forth between accounting and CRM, but you probably do not want to retain all data of all views that have ever been opened, that is the complete possible state tree without any pruning, within the application forever or even initializing the whole tree to its initial state on load.
Are there idioms, patterns or libraries which solve this or am I missing something?
As a partial solution which solves retaining all the data I imagine something like resetting parts of the state to their initial state when navigating away from certain parts of the application given some declarative rules such as:
set accounting = {} (indirectly, through an action such as ACCOUNTING_LEAVING) when <Accounting/> receives componentWillUnmount
delete/set crm.mail = {} when <MailEditor/> receives componentWillUnmount
I have not seen examples which clean up the state in any way. Many "list + detail view" examples store state like { list: [...], detail: {...} }, but when switching to the detail view the list is neither emptied, nor nulled, nor deleted. This is nice when I might return to the list view a couple of moments later, but not when using an application 9 to 5 without ever releasing data.
A few related thoughts:
Unless you're expecting dozens or hundreds of megabytes of data to be cached in your store, you're probably worrying about this too soon. Write your app, benchmark, and then optimize.
Dispatching actions to clear out portions of the store is entirely valid and reasonable.
My Redux addons ecosystem catalog may have some libraries listed that would be useful. In particular, the Component State and Reducer pages point to some libraries that do things like dynamically adding and removing reducers from your store, and resetting state.
You may also be interested in my collection of high-quality React and Redux tutorials.
Overall, how you organize your state, when you update it, and what you update it with is up to you. Redux simply provides a pattern and rules for the process of doing the updates.
Suppose a complex component is subscribed to the redux store. The first time the component is mounted, we aggregate a lot of data from the store and create a "ModelView" object.
Then, imagine that this component receive an event to update itself because there's a new state. It seems like the render method would need to re-aggregate all the data from the store to know if there's a difference. I.e. we cannot do a simple comparison because the ModelView object is different than what's in the store.
You may ask "Why a ModelView", why not just read data from the store in render(). This is a fine approach for simple pages, but for complex pages the lag is noticeable and it is just not possible.
Also, a view may have an internal state that is different from the store. For instance, maybe a few tasks have been updated in the store, but we don't want to change the UI because that would be confusing for the user.. we'd rather show a "Click to see new change" button for instance. One approach to that is to store everything in the store.. both the ModelView AND the normal state.. but isn't that overkill? Or said differently, shouldn't the ModelView be stored inside the component itself?
Computing Derived Data is a recipe describing how a memoized “view model” can be derived in a composable way from the Redux store thanks with Reselect.
seems like I am thinking in the wrong direction.. I have a react app that's using redux. Now I have a reducer that's getting data from a server. For one Component, I need the data to be transformed which I'd like to do within the reducer.
But if I transform the data, it's transformed for all subscribers isn't it?
So is it possible to transform data within a reducer on the fly, but doesn't save the transformed data within the state? (Well this sounds like a dump question..)
Often components will need special data that can be derived from store state, but which isn't store state. As one comment suggests, you can just write a function that does the transformation, and call it from the component. These functions are sometimes called 'selectors', since they select and transform parts of the state. However, this can cause problems, since the value will be re-computed every time any state changes, and since it's derived data, everything depending on it will be re-rendered.
There is a redux extension library that provides a solution to this problem, by allowing you effectively to declare the precise parts of the state that your selector depends on. This means it will only be recomputed when these parts change, avoiding the re-render every time problem. See:
http://rackt.org/redux/docs/recipes/ComputingDerivedData.html
and https://github.com/rackt/reselect
You may choose to completely encapsulate your store state, and have components only ever access the state via selectors. This has the usual encapsulation and related benefits (e.g. insulating your components from some re-factorings to the store state).