Problem
I am trying to design webapp with a fairly complex state, where many single actions should trigger multiple changes and updates across numerous components, including fetching and displaying data asynchronously from external endpoints.
Some context and background:
I am building a hybrid cytoscape.js / redux app for modeling protein interactions using graphs.
My Redux store needs to hold a representation of the graph (a collection of node and edge objects), as well as numerous filtering parameters that can be set by the user (i.e only display nodes that contain a certain value, etc).
The current implementation uses React.js to manage all the state and as the app grew it became quite monolithic, hard to reason about and debug.
Considerations and questions
Having never used Redux before , I'm struggling a bit when trying to conceptually design the new implementation. Specifically, I have the following questions / concerns:
Cytoscape.js is an isolated component since it's directly manipulating the DOM. It expects the state (specifically the node and edge collections) to be of a certain shape, which is nested and a little hard to handle. Since every update to any node or edge object should be reflected graphically in cytoscape, should I mirror the shape it expects in my Redux store, or should I transform it every time I make an update? If so, what would be a good place to do it? mapStateToProps or inside a reducer?
Certain events, such as selecting nodes and/or edges, crate multiple side-effects across the entire app (data is fetched asynchronously from the server, other data is extracted from the selection and is transformed / aggregated, some of it derived and some of it from external api calls). I'm having trouble wrapping my head around how I should handle these changes. More specifically, let's say a SELECTION_CHANGE action is fired. Should it contain the selected objects, or just their IDs? I'm guessing IDs would be less taxing from a performance point. More importantly, how should I handle the cascade of updates the SELECTION_CHANGE actions requires? A single SELECTION_CHANGE action should trigger changes in multiple parts of the UI and state tree. Meaning triggering multiple actions across different reducers. What would be a good way to batch / queue / trigger multiple actions depending on SELECTION_CHANGE?
The user needs to be able to filter and manipulate the graph according to arbitrary predicates. More specifically, he should be able to permanently delete \ add nodes and edges, and also restrict the view to a particular subset of the graph. In other words, some changes are permanent (deleting \ adding or otherwise editing the graph) while others relate only to what is shown (for example, showing only nodes with expression levels above a certain threshold, etc). Should I keep a separate, "filtered" copy of the graph in my state tree, or should I calculate it on the fly for every change in the filtering parameters? And as before, if so, where would be a good place to perform these filtering actions: mapStateToProps, reducers or someplace else I haven't thought of?
I'm hoping these high-level and abstract questions are descriptive enough of what I'm trying to achieve, and if not I'll be happy to elaborate.