How to handle multiple stores of same type in Flux / ReactJS?
Asked Answered
G

1

7

I'm new to Flux/React and I'm having a hard time understanding some of the fundamental architecture decisions:

  1. I know all stores are meant to be singletons, but are they all created at app start, or can the lifetime of a store be smaller, specific to the user's actions?
  2. Can I have multiple instances of the same store type, each initialized with a different context?

Unfortunately, all the examples I've seen seem too simplistic to answer these questions. Let's start with Facebook's chat app example. There are multiple threads each with messages. MessageStore holds all the messages for the entire app and a method called getAllForThread(id) returns a filtered subset of messages. When a message comes into ANY thread, it emits a change notification that causes the MessageSection react component to re-fetch data (regardless of which thread the user is viewing). This obviously doesn't scale. What if we had 10,000 threads each with lots of message activity? Here's how I decided to solve the issue:

  1. Each MessageStore is initialized with a thread id.
  2. Create a singleton MessageStoreFactory that creates and manages MessageStores.
  3. When the user clicks on a thread, instead of the React component subscribing to a global MessageStore, it asks the MessageStoreFactory for the MessageStore for that specific thread.
  4. If the factory already has a MessageStore for that thread, it returns it. Otherwise it creates one, kicks off an async task to fetch the initial data for it, and returns it.
  5. When the React component is torn down (let's say the user navigates away from it), it notifies the Factory that it's all done with the Store. Using reference counting or some other cache logic would allow the Factory to prune unused stores.

How far off base am I with this approach? Is there a simpler approach that still scales?

Gentilis answered 14/5, 2015 at 21:16 Comment(1)
"This obviously doesn't scale." - I would be careful not to make assumptions about how Stores and components will behave at scale. React's diffing minimizes DOM operations, and "componemtShouldUpdate" can catch things before the render process. You can be clever about what your update data fetcher asks for (maybe ask for most recent changes since messageId #16456 instead of getTheMessages).Disesteem
A
1

It seems easier to make smarter data fetching according to the thread which user is viewing. Could I see this facebook's example at some blog-post or presentation?

Aircrew answered 15/5, 2015 at 7:30 Comment(8)
Updated my question with a link. Here it is again.Gentilis
Fetching the data isn't necessarily the issue here. If the MessageStore holds all the messages for every thread, it's going to produce a change event every time any messages comes in. This will make the MessageStore incredibly noisy. Even if fetching is more optimized, it will still result in a lot of react components handling those events when they're not really interested. That's the part that doesn't seem to scale.Gentilis
you may need to implement shouldComponentUpdate method to prevent re-render. Since this method will be called really often it need to be fast. Bu you may use immutable data structures (facebook.github.io/immutable-js)Aircrew
But you may use immutable data structures. This will make shouldComponentUpdate method really simple and fast. facebook.github.io/react/docs/advanced-performance.htmlAircrew
I'm going to mark this answer correct, but more because of your suggestion to use immutable-js than your actual answer. We're still nervous about scalability, so we plan to look at approaches that involve flushing store data caches and intelligent fetching. I'm certain immutable-js will be instrumental in the final solution.Gentilis
@Liubko Nonsense. shouldComponentUpdate would still be called for each and every component that subscribes the store. This is what's unacceptable.Diffractive
@SzczepanHołyszewski I didn't say that shouldComponentUpdate wouldn't be called... I said that it will be called often, that's why it need to be fast. Unacceptable would be to call render on each update, not shouldComponentUpdate.Aircrew
Calling a function N-1 times just to determine that we shouldn't do anything and only 1 time to determine that we should do something is absolutely unacceptable from software quality standpoint. It's just bubblesort-level disgusting. The information as to which single instance should update is available when we dispatch the change to the store, and then the opinionated framework forces us to lose this information and later recompute it in O(n) time every time. This is insane.Diffractive

© 2022 - 2024 — McMap. All rights reserved.