I'm using Redux and React in an online food-ordering app.
When the user removes an item from their basket, I need to fire off an XHR request to the server to compute the new total price for the basket. When this XHR completes, I update the redux store and render the new price. I'm using Redux thunk to manage this async operation.
There is a problem is a user removes two items from the basket in quick succession. The user removes the first item, and I fire off an XHR to get the new price. Then the user clicks a button to remove a second item, and a second XHR is fired off.
The UI will be in an incorrect state if the second XHR completes before the first - the price of the basket with only the first item removed will be shown.
To work around this, I want to cancel the first (in-flight) XHR when the user clicks the button to remove the second item. To cancel the first XHR I need to keep track of the promise object (I'm using axios to manage XHR).
It makes sense to me to store the in-flight XHR in the redux store. Is it bad practice to store promises in Redux like this? It seems to be frowned upon - Redux should really just be storing plain data.
This is covered in the Redux FAQ, at http://redux.js.org/docs/faq/OrganizingState.html#organizing-state-non-serializable :
It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.
Generally, any async behavior like this is handled externally to the Redux store, via promises or middleware like redux-thunk, redux-saga, or redux-observable. For some comparisons between these approaches, see the recent articles Redux 4 Ways and 3 Common Approaches to Side-Effects in Redux.
Related
Building a simple E-commerce store with Nuxt and Prismic.
I have this very simple action in my store:
async GET_ALL_CATEGORIES({commit}) {
// gets all the categories from prismic
// Set categories to the state
}
My question is, when I move around the application from / to /category1 to /category1/product1 should I be dispatching this action everytime?
Would one save this array of categories in localStorage?
Should I have an if block in my asyncData that checks for the categories state and if it is empty, dispatch the action, otherwise use whats in state?
How do the pros handle this situation?
Thank you!
It depends on how often you think your 'categories from prismic' would change. If not very often then you can save it to the store and then just read from the store.
Otherwise you may want to query your API etc on every page load, probably in mounted()
EDIT: You many also want to set an expiry date on the state so that it can pull in fresh data at intervals
For example, let's take a simple web application with comments feature. In my understanding, when a user posts a new comment, the following would occur:
display UI loader;
update the front-end state;
send a fetch request to the API to post a new comment;
Wait for the response;
send another fetch request to the API to request the new list of comments;
waiting;
update the front-end state with new comments;
update UI to reflect the new state with a new comment;
And the user needs to wait while front-end app interacts with back-end on almost every data change. The same way we did it earlier with PHP/Python/Ruby, ajax, server-side rendering and templates.
That makes me think what's the point of adding so much front-end complexity with something like react, when the result is basically the same.
My question is: are there any alternative approaches to this? Is it possible instead to do the above case the following way:
user clicks to post a comment;
update the front-end state;
update UI to reflect the new state with a new comment;
sync front-end state with API DB in the background;
Well, as your question is tagged react, you could use the Apollo library (it is intended to work together with graphql on the backend) for data fetching. It offers a feature called Optimistic UI, which will be update the frontend with the respected result, until it receives an answer from the backend. If the expected result differs from the received one, the component will change the UI automatically to the real result. In case of an error, it will show an error message.
You definitely could, your first method is just way of doing it.
Apart from 'syncing' your front-end state, another method is also to just pre-emptively update the UI (step 7 & 8 in your first method) before doing step 3-6, and only reverse the action if the API call failed. This should allow for slightly better UX for the end-user too.
I get it that you think it's waste of time for users to wait until requests are successful. However, isn't it more important to stop users from keeping making bad requests to the server?
So, what I would do is just to stop fetching data from the database every after users make requests.
Fetching the DB data to begin with and store them in redux states
Make requests to the DB while holding users from doing anything
Make changes to the redux state if the requests are successful
But what you want to do could be done like this
Fetching the DB data to begin with and store them in redux states
Make changes to the redux state while making requests to the DB in the background
Depending on whether the requests fail or not, roll back the change users made from the redux state
I am working on online shop. I have an order reducer, where I can hold my order. After page refreshing my store becomes empty (which is obvious). The main idea is to have my order saved for some period of time (e.g, 20 mins). Also, I want to save only piece of my store (order state). So, I decided to persist my state to localstorage
But here is a trick. How to do it correctly from architecture and patterns side? I have a few ideas:
Subscribe to my store using store.subscribe() and rewrite my localstorage on every store change. It will be a bit strange, because I need to parse my store using, take a piece of it and push to localstorage. Also, my callback will be called on every change, it may affect productivity.
Do it right in the dispatcher (this is an anti-pattern I suppose):
const addToOrder = orderItem => ({
type: actionTypes.ADD_TO_ORDER,
payload: orderItem
});
export const addItemToOrder = orderItem => dispatch => {
// localstorage.setItem() ...
dispatch(addToOrder(orderItem));
}
Use libraries like
https://www.npmjs.com/package/redux-persist
https://www.npmjs.com/package/redux-localstorage
https://www.npmjs.com/package/redux-localstorage-simple
But in this case, how to clear my localstorage in 20 minutes after closing tab?
So, how to persist my state correctly and how to clear localstorage ins some time?
Thank you in advance for your help!
All ways are possible. Second also, as you use action creator to do additional work. For example action creators are used for data fetching, so storing data to localStore is not a problem.
I suggest to use option 3. It provides best separation of concerns. Code for storing data is located in single place and to spread over several action creators.
Unfortunately, you'll not be able to set expiration time for localStore items. But as localStore is accessed only by your app, you may leave items forever, but adding storage date/time. And during app start next time just check time and if data more than 20 min old, purge it. You can do this check in config.merge function.
If my client-side application displays a list of items requested from my API, and a user deletes an item, is it best practice to then again call the list GET at the end of the successful HTTP DELETE promise and update the view? Or should the application state simply be updated locally after the delete, without hitting the API again?
I understand optimistically updating your application, but, that is more for view update performance rather than reducing server calls.
You should make another GET request to update the list if the list data may change without user interaction, eg: server-side updates, or another session that can change the same list
With the performance aspect, let the user see the entry deleted ASAP, then very shortly after they will see the updated changes (if there are any), and it won't disturb them.
If there is a deletion error, refresh the updated list regardless
EDIT: I'd also suggest using websockets
I have a component that takes user input. When they save, I use an action to update a store's state
In response to this new information, a results component needs to run an async operation and then respond when new information comes back.
No matter what I try, I seem to be left with a hack setTimeout or a dispatch-within-dispatch error.
The async operation is defined via a datasource and has its own store as outlined here. What's the correct way to structure this behavior?
User input is received by input component.
Input component uses an action to update a store's state
Currently, the store attempts to start the async operation needed by the output component
My choice at this point seems to be Dispatch-with-dispatch error or a hack solution involving setTimeout. Neither feels correct.
What am I missing?
Ignore the examples about DataSources. Do not use registerAsync in stores.
Instead, use actions to perform async behavior and have results update stores. In the example you gave, do this from the input component:
Action1.updateStore()
AsyncAction2.run()
Then, use a store watching AsyncAction2 actions to update and inform result components.
If you're sure that you want to be dispatching at that point and just want to avoid getting the "dispatch within a dispatch" error you can use alt's .defer method (see: http://alt.js.org/docs/actions/).