Search code examples
javascriptreactjsflux

Flux: how to deal with objects that generate other dependent objects


Context: we are building a complex 3D "Sims-like" web app with React/Alt.js. Users can add simple objects in the 3D scene (a cube), but more often they will add what we call a "prefab", which is an assembly of several simple objects (15 cubes make a structure) based on some user's params (length, height, ...).

So we have an ObjectStore, with all simple objects, and PrefabStore (which only hold user's params to generate the prefab).

We could generate this prefab and its objects only in the React layer (this way the prefab render is always in sync with the prefab's params in the store), but for technical reasons we need all these prefab's simple objects to really exist in the store layer. In other words, we need to generate the prefab's objects in the store (ObjectStore since it's where simple objects are stored).

The question is: where (in the store layer), when and how to generate the prefab and all its dependent objects, and where should we store generated objects, knowing that:

  1. When prefab's params are updated, we need to re-generate and update objects (existing objects could be moved, rotated, completly removed).
  2. We can't compute prefab's generated objects in the React view layer since wee need these generated objects in the store layer (because these objects could interact with others, we also need them when we generate a file with all existing objects).
  3. Generate a prefab and its dependent objects is a complex and slow task: we can't call this generate function each time we need to render the prefab. Furthermore, as i aid in the previous point, we need a reference to generated objects so they have to exist in the store.

To help understand what is a prefab and a simple object, and why wee need the prefab's objects to exists in the store layer, here is a screenshot of our app: enter image description here

My solutions:

  1. Generate prefab and dependent objects in a React component, on-the-fly.

Pros: prefab render and dependents objects are always in sync with prefab's data. When prefab's params are updated, React automagically render prefab and generate objects again.

Cons: objects don't really exist. They are not in ObjectStore so I can't interact with them (display object list, generate a file with all objects, ...).

  1. Generate prefab and dependent objects once in action, then populate dependent stores (ObjectStore, PrefabStore) with generated objects.

Pros: all objects are stored in their own Store.

Cons: when you update a prefab (move/rotate/resize), it's difficult to update all dependent generated objects and you need a bunch of store lsitener in ObjectStore to ensure objects are in sync with the prefab they belong to.

  1. Generate prefab and dependent objects on-the-fly, but in the store with memoization. Pros: dependent objects are always in sync + objects really exists in the store layer (not sure how to handle this memoization in two different stores: PrefabStore and ObjectStore).

Cons: I don't know how to handle the memoization in two different stores: PrefabStore for the prefab object (which still has position/rotation properties) and ObjectStore for generated objects.


Solution

  • It's tricky to answer these kinds of architectural questions - you are the expert on your own system and domain, but here goes anyway:

    The basic flux rule is that a Store is responsible for mutating its own state in response to an Action. Additionally, there are good general code organisation practices, such as having low coupling and high cohesion, etc.

    One option would be:

    1. Some kind of Prefab model object, that knows about the parameters of a single prefab 'template' and has a generate method to create and return the appropriate Objects (perhaps the generate method has to take some position info or something as params). The prefab model can decoupled from any stores, in a separate code module. The generate method can be a pure function, in its own module, if you like.

    2. The Prefab Store can directly store prefab models (simplest probably), or just the data needed to construct them.

    3. The Object Store has a handler for the ADD_FROM_PREFAB Action that queries the Prefab store for the appropriate Prefab model data/instance, calls generate on it and finally adds the returned objects into its state.

    4. UI then just renders the scene from the ObjectStore, not the prefab store (though presumably the Prefab store is used for a prefab library UI as well?)

    With this approach you can unit test the prefab model and object generation in isolation, and re-use it where you want easily. The store code is also fairly simple glue that's easy to test. And the UI doesn't need to worry about prefabs in the rendering part.