Flux - Stores' data lifecycle - javascript

There's one thing about Flux (or at least about its implementations) that I don't quite understand.
It's about internal data management of Stores. I'll try to explain my question by breaking it down into points.
Let's imagine I have some app with client-side routing.
As I understood Stores are singletons. Somewhere they store some data (e.g. an array)
User clicks somewhere and navigates to some part of the app. Correspoding Store fetches some data.
Let's imagine that it's a really big amount of data. So big that it takes a lot of resources and even makes page laggy.
After a while user navigates to a different route. What happens with the internal data of the Store mentioned above?
As far as I understood, it remains intact. At least until user navigates to original route and the Store changes its state.
And before that happens the Store holds big amount of data even when it's not needed.
Can someone clear this out for me? Thanks.

Store just listen the dispatcher(actions) and somehow react on it. In example you mention - yes, it will hold the data at least you don't use weakmap or kinda, but you also can listen actions on changing routes and process your data in this case.

Related

js / vue app doing CRUD, how can I track what needs updating?

I'm working on a vue app that uses vuex and gets objects from an api. The tables have paging and fetch batches of objects from the api, sometimes including related entities as nested objects. The UI allows some editing via inputs in a table, and adds via modals.
When the user wants to save all changes, I have a problem: how do I know what to patch via the api?
Idea 1: capture every change on every input and mark the object being edited as dirty
Idea 2: make a deep copy of the data after the fetch, and do a deep comparison to find out what's dirty
Idea 3: this is my question: please tell me that idea 3 exists and it's better than 1 or 2!
If the answer isn't idea 3, I'm really hoping it's not idea 1. There are so many inputs to attach change handlers to, and if the user edits something, then re-edits back to its original value, I'll have marked something dirty that really isn't.
The deep copy / deep compare at least isolates the problem to two places in code, but my sense is that there must be a better way. If this is the answer (also hoping not), do I build the deep copy / deep compare myself, or is there a package for it?
It looks like you have the final state on the UI and want to persist it on the server. Instead of sending over the delta - I would just send over the full final state and overwrite whatever there was on server side
So if you have user settings - instead of sending what settings were toggled - just send over the "this is what the new set of settings is"
Heavy stuff needs to be done on the server rather than the client most of the time. So I'll follow the answer given by Asad. You're not supposed to make huge objects diffs, it's 2022 so we need to think about performance.
Of course, it also depends of your app, what this is all about. Maybe your API guy is opposed to it for a specific reason (not only related to performance). Setup a meeting with your team/PO and check what is feasible.
You can always make something on your side too, looping on all inputs should be feasible without manually doing that yourself.
TLDR: this needs to be a discussion in your company with your very specific constrains/limitations. All "reasonable solutions" are already listed and you will probably not be able to go further because those kind of "opinion based" questions are not allowed anyway on SO.

Passing values between components: Pass References vs Subjects

tl;dr: Why not pass variables by reference between components to have them work on the same data instead of using e.g. BehaviorSubjects?
I'm writing a sort of diary application in Angular 8. I have two components (Navbar and Dashboard) and a service (EntryService).
Navbar lists the entries, Dashboard provides the textarea, EntryService glues them together and communicates with the database.
While debugging the application I stumbled upon a way to communicate between the service and a component that i haven't thought of before.
By accident I passed a variable (entry: Entry) from the Dashboard by reference to the EntryService. The service saved to the database getting a unique ID back and saving this ID into the entry variable. This change immediately reflected to the Dashboard because of the 'passing by reference'.
Until now I was using Subjects to update the components on changes, but passing references around seems to be much simpler, because I want to work on the same data on both components and the service.
I've studied Angular for a while now and not read about this approach, so I'm wondering if it is a bad idea or design and if yes why?
Thanks for your answers!
Passing by reference can be handy. But as a general approach to keep the application components in sync it has some draw backs. With Subjects you can easily investigate in which places of the application the value of the Subject will be changed by checking where the Subject.next() function is being called. When you pass your object by reference to a hundred components/services it will be much more difficult to find out, which of them modify the object and more importantly when, becaue often you want to trigger other changes afterwards. When you subscribe to Subjects, you get notifications about changes and can react to them. Subjects and Subscribers are an example for an Observer/Observable pattern, it allows you to decouple your application logic. And they are much more flexible, for example you can have a Subject which can return the last x number of changes or you can debounce the changes when you track user input, you can apply filters to them etc.

Redux/sagas: Approach for larger API's

I've worked with Redux/sagas workflows on small projects based off of this real-world example, but the logic of those is not nearly as complex. How should I be approach working with a more comprehensive api (i.e., Reddit's API), without making things overly verbose?
Do I make a const for every endpoint? i.e.,
export const fetchUser = login => callApi(`users/${login}`, userSchema)
Should I be worried about managing the entity cache?
Is there a way how to further reduce complexity/boilerplate (i.e. further grouping request types with get/put/post/delete for the same endpoint)?
Are there any examples out there that deal with bigger/more complex than the real-world?
I think the answer depends on how fluid you want your components to be.
I'm working on a large codebase using sagas, our pages are separated into "types", for example a "list" type, "form" type etc.
We have one saga responsible for fetching content, while each pageComponent when being rendered is responsible for supplying the endpoints.
this allows a very modular approach, to add a component you need to deal with one subsection of your file system.
Our pages are mostly a configuration file that contains all this information, and we use this configuration to render a "generic" component with the correct data.
Saga reusability
I see Sagas as sequential processes, they can be for async fetching data, but they're also useful for anything that needs to be dealt with in sequence.
These "Flows" are sometimes very similar in a codebase, and those are the ones you want to generalize.
Like you said, the most common operations are CRUD for any endpoint, that can be easily grouped together.
Login is extremely different than loadUserList and different things need to happen afterwards, however loadUserList and loadRepoList is extremely similar.
Things that impact reusability
Your ability to control your API's, if you can dictate the shape of the API you consume, you can get away with even more generalizations in front end.
The shape of the application(Front-wise) - are your pages strangely dependent on one another's state? for example it's not uncommon for insurance programs to have forms that link to one another, you can fill the first 3 forms in any order you want, but once all three are complete the 4th unlocks.
Each of these dependancies will normally have their own saga that controls the flow of your use story.
Does your application require syncing? You can easily create sagas that automatically sync data with your different endpoints and update your Redux State, there's much to consider here, including if we decide to interrupt the user with new data(we might want to let him know that the form he's editing has out dated data) - syncs require a distinct saga as there are usually various business rules when to sync what data - if the rules are very different this can force you to create multiple sagas)
Common Sagas that can be unified
UserSagas - login, logout.
FetchData - fetch a single record, or a collection.
DeleteData - Delete a single record, or a collection of IDs
Data Syncing - Updating your local data from a remote periodically.
Regarding the entity cache
Entity cache is just a name they picked, but this goes back the points mentioned before.
Does your application run on stale data, or do you fetch from the server every time your component is loaded?
If the data is only fetched once and you display stale data, you'll store it in a type of cache(that's basically the redux store).
If you show stale data, this is the way to go.

How to deal with component state with redux?

I have been using vanilla React for a while, and have now decided to take a closer look at Redux for a new project I am doing.
At first I got the impression that all user activity should result in actions, with one of the main reasons being that you would be able to reconstruct any application state by just playing back the appropriate actions.
The problem with this, however, is that you put a lot of stuff in the store that in reality does not feel like application state. Stuff like "If I focus on this input, the label turns green" does not seem like state fitted for being represented in the application state of an application that is potentially composed by hundreds of components. These things make total sense with the typical todo-tutorial, but it can be difficult to see how it will turn out in a more complex scenario.
Then I read some more, and found that the general opinion, backed by creator Dan Abramov, is that you should usually combine local component state with the application state (store). "Whatever seems least awkward" seemed to be the rule of thumb for where to store state.
On one hand this makes total sense: The things that are really application state, and are relevant for multiple components should be in the store, while the strictly presentational details that only concerns one single component should be handled using normal react state. On the other hand this approach confuses me a bit, because of what I wrote in the beginning: Isn't a big part of the point with redux that you avoid having the state distributed among the components, and that you are able to recreate state by just storing the actions?
I hope someone can shed some light on this concern, because it has been bothering me, and it is something I think I should get a solid opinion about before trying to build something complex with redux.
What state you put where is entirely up to you. Sometimes it may make sense to put everything in Redux, sometimes it may make sense to keep stuff in a component. I recently saw some good rules-of-thumb:
Do other parts of the application care about that data?
Do you need to be able to derive further data from that data?
Is the same data being used to drive multiple components/features?
Is there value to you, to being able to restore the state to a given point in time (ie: time travel / debugging)?
Do you want to cache the data, ie: reload it from state if it's already there instead of requesting it again?
(Credit to https://www.reddit.com/r/reactjs/comments/4w04to/when_using_redux_should_all_asynchronous_actions/d63u4o8 for that list.)
Also see the Redux FAQ on this topic: http://redux.js.org/docs/FAQ.html#organizing-state-only-redux-state .

Flux architecture misunderstanding in example chat app

I'm trying to understand the Flux example chat app. The authors mention this unidirectional data flow:
However, in the example app there are dependencies between Action Creators (ChatMesssageActionCreator) and Stores (MessageStore), and between Stores (MessageStore, ThreadStore) and Web API Utils (ChatMessageUtils), which seems to be against the unidirectional data flow rule:
Is it recommended to follow the given example, or should one design a better pattern?
Update
I figured out that the ChatMessageUtils doesn't belong to Web API Utils, so the two arrows from store shouldn't point there, therefore maybe they're okay.
However the connection between the ActionCreators and the Store seems still strange.
The example is a bit forced, and it was created with the purpose of trying to show how waitFor() works. The WebAPI aspect of the example is pretty half-baked and really should be revised.
However, even though MessageStore.getCreatedMessageData(text) passes a value to the store, it's still a getter. It's not setting data on the store. It's really being used as a utility method, and a good revision (pull request?) would be to move that method to a Utils module.
To improve upon the example for the real world, you might do a couple things:
Call the WebAPIUtils from the store, instead of from the ActionCreators. This is fine as long as the response calls another ActionCreator, and is not handled by setting new data directly on the store. The important thing is for new data to originate with an action. It matters more how data enters the system than how data exits the system.
Alternatively, you might want to have separate client-side vs. server-side IDs for the messages. There might be few advantages of this, like managing optimistic renderings. In that case, you might want to generate a client-side id in a Utils module, and pass that id along with the text to both the dispatched action and the WebAPIUtils.
All that said, yes the example needs revision.

Categories

Resources