Redux: How to manage conflicting state across routes? - javascript

In my application, on route1 I get a list of items from an api call. The component is connected and the items are saved in redux store and passed to the component as props. Now, on route2 I again need this list of items.
For now, i am fetching the list of items again when we move to route2
Does it make sense to reuse the list of items which is already in global state? If yes, how do we decide when it is stale and when to refetch?
If it doesn't make sense to reuse the list of items, should i clear the list when moving away from route1/when loading route2? Because otherwise, my component in route2 cannot start with an assumption that the list would be empty on load, and I would have to put an extra check for whether or not the list is empty. This would make my component kinda aware of the global state structure.
Does it make sense to name these pieces of state differently, so that one doesn't interfere with the other? This doesn't seem right, as both the functionalities are same, and we wouldn't want to increase the size of global state for this.
is redux or any global state management library not a good choice for handling this kind of state? This seems like state local to a route, which should not interfere with local state on another route, so it is not truly global. Should we only keep global state in redux ?
I have previously been using useReducer with axios calls to do this. The state in that case was local to each of the components/route, so they didn't have to care about whether or not the state has been populated by someone else. This approach had problems with sharing state between routes, but local state problem was handled well.

In this situation, I think you should store the item list in the global state as readonly data. When a route component initialize, it should clone this item list from the global state and store it as local state.
This way ensures that the item list data is shared across multiple components without having to refetch it for every route while each component can choose to do whatever they want with its local data without affecting other components. Also, when the component unmounts, it will clean up its local state so you don't have to worry about memory leak due to multiple copies of the item list.

I have been in this situation and the approach I used was as follows:
Keep one state for both routes. Since that's the only point of
keeping a single source of truth across the application. If we want to keep a separate list for both routes then we can directly use state which I think is not required here.
Fetching of the list should be done in componentDidMount of
the first route and in route 2 you can again fetch the list and compare the data based on some checksum if we have new data or not if we have new data update the original list. In this, we don't have
the problem of stale data too.
Maybe you can have a different use case but check if this approach works.

Related

How to think about this code design in React

I'm learning react and having some trouble getting my head around some code design. I have a Session component that has several Activity components in my project. In the Session component I also have a Timeline component and I need to show the total duration of all of the events. So I need to have the start time for each of the Activities in the Session component and the end time of the last. I know of "lifting state up", but I find it a little strange in my OO way of thinking from C++ to store the data in the parent and not where it "belongs". What if I later need some other data from the activity.. Then I would lift parts of the Activity data up and store some of it in the Activity.. seems quiet messy?
I thought of also having a ActivityData object and store a list of them in the Session and pass that in to each of the activity to display it there. Another way I thought about would be to have a SessionModel object and a ActivityModel object and have this seperate from the component all together and pass these models in for rendering in the component.
I am also just getting into typescript and moving my code into that. I was thinking that I could define a custom ActivityData type in the same file as the Activity component and still store the list in the Session, but then at least its more explicit that the data belongs to the activity.
What is the right (or React) way of doing this?
You are right in your thinking and yes it isn't necessarily an OO way of doing things but more of a functional programming approach
Each component can have state, and it should store that state in it's own component. If that state is then needed by another component you can pass it down as a prop. However, if it isn't a child component that needs it then like you said you should lift state up.
The next problem happens when your app starts to grow. So then you need to make some choices. You should split your components up so they don't get too big. You can have some more logical components and then have some presentational components that don't handle logic but essentially just take props and render the views from you.
However, your app is still growing so at this point you might want to invest some time in introducing a state management tool to your app. React has the context
api built into so you can use that. or you could use a library likeredux. Redux is particularly good at abstracting state to a "global" store and you each component can "connect" to the store to access the state. Really good for apps where you have lots of shared state and lots of components need to know about similar pieces of state
In terms of Typescript then it's certainly a wise idea to include that as the language is heading that way. You can keep types in the same file or keep them in the same directory but have a .types.ts file that you import into your code and declare your types/interfaces in there

Which type of data and when should I initialize in the vuex state?

I'm starting to learn about vuex. I have the question should I set this data from the Store or should I load it on the component?
For example, In my app, I load all users (firebase) from a Store Action and read it from the Getters, but when it comes to load one user data, should I fetch it from the state and then to the component or from the component itself?
I just want to make sure to make my life easier when updating or adding a new feature on the app.
Your store should be your only source of truth for global state.
This means that any component that read data should read from the store. This ensures consistency. Of course each component may need some local data, that it gets using other means and can alter the data that it gets from the store, but it should read from there.
Now you only have a dilemma regarding who should write to the store (using mutations and actions). This depends heavily on your use cases. It is perfectly acceptable to write from the components itself.
There are use cases where populating some data from outside any component makes sense. Probably the most common case is auth credentials. It is easier and cleaner to populate auth credentials before mounting the app for instance so you have one choke point for dealing with authed/unauthed users.
Bottom line is, writing to the store depends on your use case and there's no silver bullet here.

React - is it wrong to rerender on props change?

I have json data I get from database in my simple todo list. I have implemented it so I save these data in props and then pass it onto child components. The only way I use state right now is for filtering these data: (show all, show completed, show ongoing).
Now I want to add backtrace to database. Which means adding new items/deleting old ones. The problem is if I implement add button that adds new task to database it will not rerender the application automatically so the change wont show until I refresh the page.
So my question is. Is it correct approach to force call render in React in this situation? Or should I completely revamp the application and change the array of tasks which is prop now to state and update it at the same time while I update the database?
Thanks for answer :)
I think that need to rerender is based on whether the component should be updated or not. And in this case it should since there is new item.
As for moving to state I don't think that you need to rewrite your component to use state instead of props. You can just implement shouldComponentUpdate and check if list of todos has changed (be careful to not mutate the todo list prop!).
If you're using React.PureComponent then you don't need to bother with shouldComponentUpdate, it will update automatically on any state or props change
Using your data (in Json) as props for your React Function Component or Class Component is perfectly fine and frequently used.
Assuming that you use a Class Component (or just you React App component) and keep the data up-to-date in the state of that component, you could add member functions to add and delete the items. I would recommend to keep user interface in sync with your user actions, and maybe have a form submit handler to process all database changes (if this is feasible for your situation).

React router - views with dependencies

In my application, there are views with dependencies. For example, in one view a user could select an item from a list (generated on the server), and in next view the user would perform operations on the item. The item is passed to the second view in props. I'm moving to using react router, but there are some difficulties:
I can't use props for transferring data anymore. What would be a preferred way to pass data? Do I have to use redux?
Users can navigate from any view to any other view by directly using url. However, some transitions don't make sense: e.g. user navigates to item editing view from somewhere else, and therefore does not have an item selected. Is there a way to limit allowed transitions?
This is a very broad question, but I'll take a stab at it.
Can you use Redux? Sure, Redux is good for centralizing your state which can easily be shared among your components. As far as limiting the url's they have access to, I would use your reducer to look at your current state, if you're using Redux and if data is not there, meaning they should not be at this step, use a javascript redirect to where they should be instead.
Finally, you don't have to use Redux to share data between components this could be done by setting global variables your components can access, but cross component communication is where Redux shines.

Should data go in a redux state tree?

I am a bit lost on what to keep in the state tree of Redux.
I saw two conflicting statements on what to store in the state tree(s).
React doc tell us that only user input should be stored in state trees.
The original list of products is passed in as props, so that's not state. The search text and the checkbox seem to be state since they change over time and can't be computed from anything. And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox.
Redux doc tells us that we often should store UI state and data in the single state tree:
For our todo app, we want to store two different things:
The currently selected visibility filter;
The actual list of todos.
You’ll often find that you need to store some data, as well as some UI state**, in the state tree. This is fine, but try to keep the data separate from the UI state.
So React tells that we should not store data (I am talking about data of the todos) and, for me, Redux tells the opposite.
In my understand I would tend on the React side because both React and Redux aims to predict a UI state by storing:
all what can't be computed (eg: all human inputs) and are part of the UI:
checkbox value
input value
radio value
...
All minimal data that could be use to build a query and send it to the API/database that will return the complete user profil, friends lists, whatever...:
user Id
creation dates range
items Ids
...
For me that excludes all database/API results because:
that stands on data level
could be computed by sending the right (and computed by pure reducers) query.
So what is your opinion here?
React documentation about the View Component state, but Redux documentation about the Application state. So, there is no conflicts between definitions.
If we talk about Redux - you make all your components without state (and transform stateless root component to stateful with help of react-redux's connect function). If you have large response from the server and you show your data with pagination / filters, you can treat your application state as what you see on screen and not put all data in Redux store, only what you need to render (for example, 100 rows to show page and total number of rows to show pagination). There is no restriction for this. The whole data you can put into another place. For example, in another data container in web-worker (I make a full request in web-worker and fetch from there only needed data to display).
Added after question edited:
The original list of products is passed in as props, so that's not state.
In that example, the reason why list of products isn't state - it's already in props. It means that the one of parent components have this as state.
I feel that the problem is that originally Redux was pushed really hard, and some people were so purists, that they argued for separating everything to Redux and re-rendering the whole application on every change. And then we ended up with this response of the creator, which actually only added a confusion, because redux was and still is a de-facto standard for new react applications, and a lot of tutorials assume it.
So, I feel that people are pressured from each side, and often they do some things without real understanding why they should (especially newcomers creating constants, actions and reducers). So, for those who read it, please start without redux, and keep it just in local state (but try to keep in some component like DataContainer).
For those who need redux, rule thumb is to put all async data (so all requests go through redux), and data which is needed for independent components. If components obviously located nearby, keep it in a local state and pass as props.
Redux is a very helpful library, but it's power is needed only after you start to have at least several routes, different query options and some complex UI. Before that there is a good chance that you are overengineering (but, of course, if you are sure that you will exceed this size, feel free to start with Redux). And again, you'll literally never will want to put your slider or small dropdown position in the store -- react's state serves perfectly for it.

Categories