245
votes

As a note: I've read the docs for Redux (Baobab, too), and I've done a fair share of Googling & testing.

Why is it so strongly suggested that a Redux app have only one store?

I understand the pros/cons of a single-store setup vs a multiple store setup (There are many Q&A on SO on this subject).

IMO, this architectural decision belongs to the app developers based on their projects' needs. So why is it so strongly suggested for Redux, almost to the point of sounding mandatory (though nothing is stopping us from making multiple stores)?

EDIT: feedback after converting to single-store

After a few months working with redux on what many would consider a complex SPA, I can say that the single store structure has been a pure delight to work with.

A few points that might help others understand why single store vs many store is a moot question in many, many use-cases:

  • it's reliable: we use selectors to dig through the app state and obtain context-relevant information. We know that all the needed data is in a single store. It avoids all questioning as to where state issues could be.
  • it's fast: our store currently has close to 100 reducers, if not more. Even at that count, only a handful of reducers process data on any given dispatch, the others just return the previous state. The argument that a huge/complex store (nbr of reducers) is slow is pretty much moot. At least we've not seen any performance issues coming from there.
  • debugging friendly: while this is a most convincing argument to use redux as a whole, it also goes for single store vs multiple store. When building an app you're bound to have state errors in the process (programmer mistakes), it's normal. The PITA is when those errors take hours to debug. Thanks to the single store (and redux-logger) we've never spent more than a few minutes on any given state issue.

a few pointers

The true challenge in building your redux store is when deciding how to structure it. Firstly, because changing structure down the road is just a major pain. Secondly, because it largely determines how you'll be using, and querying your app data for any process. There are many suggestions on how to structure a store. In our case we found the following to be ideal:

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

Hopefully this feedback will help others.

EDIT 2 - helpful store tools

For those of you who have been wondering how to "easily" manage a single store, which can quickly get complex. There are a tools that help isolate the structural dependencies/logic of your store.

There is Normalizr which normalizes your data based on a schema. It then provides an interface to work with your data and fetch other parts of your data by id, much like a Dictionary.

Not knowing Normalizr at the time, I built something along the same lines. relational-json takes a schema, and returns a Table-based interface (a little like a database). The advantage of relational-json is that your data structure dynamically references other parts of your data (essentially, you can traverse your data in any direction, just like normal JS objects). It's not as mature as Normalizr, but I've been using it successfully in production for a few months now.

6
I like your approach for the store structure you are using; however, how are you handling api state changes mapping to your component state changes? So say I receive domain specific data from my API, how does this translate to a generic data structure that would be found in my components?Diniden
How your components map/use store data is up to you, really. Though I think I don't fully understand your question, could you elaborate or start a chat session?Sebastien Daniel
I guess the question would be: do your components render any from the apis state, or do they only render whatever is put into the components state. I would suspect if you managed to ONLY render from the component's state, then you have found an excellent way to make your components and Containers highly re-usable even in the presence of domain specific data. If your components are rendering partially from API state AND component state, then I'm guessing you're utilizing Domain specific Containers to map the data in apis to generic lists and primitives that your components understand.Diniden
I use Redux in conjunction with selectors, which are basically memoized functionally-pure data mappers. Each component "reacts" to store updates, and if a change is relevant to it, it "selects" the data and renders accordingly. So yes, components ONLY render based on what matters to them. But that isn't just because of Redux or the store structure. Its due to the combination of an Immutable data store, a referential comparison test for data changes, and a pure selector which fetches the data the component needs, in the format it needs it.Sebastien Daniel
Hey @SebastienDaniel, could you show an example of how are you implementing the check that each component does to know if the change in the store update is relevant to it? I mean if you are using some kind of generic pattern... or if in every specific case you are checking if the specific component-related data has changed.John Bernardsson

6 Answers

258
votes

There are edge cases when you might use multiple stores (e.g. if you have performance problems with updating lists of thousands of items that are on screen at the same time many times per second). That said it's an exception and in most apps you never need more than a single store.

Why do we stress this in the docs? Because most people coming from Flux background will assume multiple stores is the solution to making update code modular. However Redux has a different solution for this: reducer composition.

Having multiple reducers that are further split into a reducer tree is how you keep updates modular in Redux. If you don't recognize this and go for multiple stores without fully understanding reducer composition first, you will miss many benefits of Redux single store architecture:

  • Using reducer composition makes it easy to implement "dependent updates" a la waitFor in Flux by writing a reducer manually calling other reducers with additional information and in a specific order.

  • With a single store, it's very easy to persist, hydrate, and read the state. Server rendering and data prefetching is trivial because there is just one data storage that needs to be filled and rehydrated on the client, and JSON can describe its contents without worrying about store's ID or name.

  • A single store makes Redux DevTools time travel features possible. It also makes community extensions like redux-undo or redux-optimist easy because they operate on the reducer level. Such "reducer enhancers" can't be written for stores.

  • A single store guarantees that the subscriptions are called only after the dispatch has been processed. That is, by the time listeners are notified, the state has been fully updated. With many stores, there are no such guarantees. This is one of the reasons Flux needs the waitFor crutch. With a single store, this is not a problem you see in the first place.

  • Above all, multiple stores are unnecessary in Redux (except for performance edge cases which you are supposed to profile first anyway). We make it an important point in the docs so you are encouraged to learn reducer composition and other Redux patterns instead of using Redux as if it was Flux, and losing its benefits.

31
votes

In some very large enterprise apps with hundreds or thousands of reducers, it's often useful to think of different areas of the app as entirely separate apps. In those cases (where it really is multiple apps that share a domain name), I use multiple stores.

For example, I tend to treat the following common functionality areas as separate apps:

  • Admin
  • Analytics / data vis dashboards
  • Billing management & purchase flows
  • Enterprise account team/permission management

If any of those things are small, just keep them as part of the main app. If they grow very large (as some enterprise account management & analytics tools do), split them out.

The best way to manage very large apps is to treat them like a composition of many smaller apps.

If your app is less than say ~50k LOC, you should probably ignore this advice and follow Dan's advice, instead.

If your app is more than 1 Million LOC, you should probably be splitting out mini-apps, even if you maintain them in a mono repo.

9
votes

This architectural decision belongs to the app developers based on their projects' needs

You are living in your own world. I am meeting with people that uses redux, because it is popular, everyday. You couldn't even imagine how much projects was started reduxing without any decisioning. I hate redux approaches but had to use it, because other developers knows nothing else. It's just an epic bubble inflated by facebook.

  • It's not reliable because parts of store are not isolated.
  • It's inefficient because you are cloning and traversing hash trie. When mutations grows arithmetically - complexity grows geometrically. You couldn't fix it by refactoring any reducers, selectors, etc. You have to split your trie.
  • When it become slow nobody wants to split it into separate applications with separate stores. Nobody wants to spend money on refactoring. People are usually converting some smart components into dump and that's it. Do you know what future is waiting for redux developers? They will maintain these hells.
  • It's not debugging friendly. It's hard to debug connections between virtually isolated parts of store. It is very hard even to analyze the amount of these connections.

Let's imagine that you have several redux stores. You will break unidirectional data flow. You will immediately realize how much connections between stores you have. You can suffer from these connections, fighting with circular deps, etc.

Single immutable store with unidirectional flow is not an elixir for every disease. If you don't want to maintain project architecture you will suffer anyway.

4
votes

Multiple stores can be helpful in the following use cases 1. If you have large components that are independent of each other in terms of data structure, behavior, application context. Isolating these components make it easier to manage your data and application flow. It also helps independent development and maintenance of your components. 2. Performance problems: not a typical use case, but if some of your components are updating very frequently and does not have any impact on other components, probably you can go for different stores.

For all other cases, you may not need to have multiple stores. As Dan says, creating thoughtful reducer compositions can prove to be better solution.

4
votes

why we can't use multiple store using redux????

This is not necessary in Redux because the separation between data domains is already achieved by splitting a single reducer into smaller reducers.


Can or should I create multiple stores? Can I import my store directly, and use it in components myself?

The original Flux pattern describes having multiple “stores” in an app, each one holding a different area of domain data. This can introduce issues such as needing to have one store “waitFor” another store to update.

This is not necessary in Redux because the separation between data domains is already achieved by splitting a single reducer into smaller reducers.

As with several other questions, 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.

Some valid reasons for using multiple stores in Redux might include:

Solving a performance issue caused by too frequent updates of some part of the state, when confirmed by profiling the app. Isolating a Redux app as a component in a bigger application, in which case you might want to create a store per root component instance. 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.

Similarly, while you can reference your store instance by importing it directly, this is not a recommended pattern in Redux. If you create a store instance and export it from a module, it will become a singleton. This means it will be harder to isolate a Redux app as a component of a larger app, if this is ever necessary, or to enable server rendering, because on the server you want to create separate store instances for every request.

official doc by redux

2
votes

Having one store in Redux is really what we need in many cases, I both used Redux and Flux and believe Redux does the job better!

Don't forget the store is in a JavaScript Object, so while you have only one store, it can be easily extended and reused, to me, having one store make it much easier to traversing using Redux dev tools and not be mixed up in big applications...

Also the concept of one store is mimicking the database for us, one source of truth which you can change it and you can access it in the browser memory...

If the whole application be well-managed, one store can be enough to manage the whole application status...