I have got an action "MODIFY_FIELD" firing on blur of div which can be modified by user. This action updates redux object containing data which will be passed to backend on submit. Since it has some sanitization logic regarding content of div, seems like it has got a delay to update redux object.
Therefore, when you click on save button, it fires an action "UPDATE_DATA", which sends old data to backend, which was in redux before modification of div.
The problem is that, I need somehow to check that "MODIFY_FIELD" action has finished and only then fire action "UPDATE_DATA".
Approach .then() does not make a sense here since I am not gonna fire "UPDATE_DATA" each time then "MODIFY_FIELD" happens.
Related
I have a Note component where a user edits a Note. Now, in my header for the app I have a button which can be clicked and you will be sent to the base product of the company - which is an external URL.
My problem is that the componentWillUnmount function (yes, this is the "old" component based API used in this particular component) does not fire and so any unsaved changes disappear.
Ideas?
I've tried adding an event listener in componentDidMount
window.addEventListener("beforeunload", this.componentWillUnmount); but my request is still getting cancelled before the redirect. I'm using apollo with graphql endpoints btw.
I don't see how rewriting to hooks can help here.
Looks like the problem is that you, actually, do not unmount component, but leave the page. React will never know about this event.
I think, you can use another approach to keep changes: send it to the backend while user filling the note. Or, maybe, easiest way is to duplicate changes in localStorage and then recover it on new load. But it feels less secure and, of course, limited by this browser/machine
Here are a few ideas you could try:
When the user clicks the button in the header, run a function/method to save the Note before redirecting.
Add an onblur listener to Note and trigger a function/method to save when Note input field loses focus
Add an onkeypress listener and save the contents of Note with every keypress (or every x seconds to batch the updates instead).
I have a few fields that, when updated, change the href of an image (which is really an endpoint of an external API that generates a PNG based on text input).
When that image loads, it triggers an action to update another component to match the image size (that it can only get after the image has finished loading). I set redux-undo to exclude that action from the history since it's not a user action.
Here's my problem: When I do an action that does NOT trigger a change, then undo that action, the state is wrong since the size has changed in between user actions.
An idea I had was to mutate the state (yeesh):
In reducer
case 'UPDATE_TARGET_SIZE':
/**
* HERE BE DRAGONS
* I am also mutating the current state since this action needs to
* NOT count as an user action
*/
state.targetWidth = action.targetWidth
state.targetHeight = action.targetHeight
return {
...state
}
While it works with no apparent drawbacks... it feels like a dirty hack. Is there another way of doing so or is it safe as long as I know why I'm mutating the state?
Can a lib like redux-saga help me? I admit I have not read its documentation since I am not making "real" API calls and I don't want to have an overkill solution.
Edit :
Here's a better example:
I type in a text input, which causes the href to change. A new image is loaded, which triggers the action that is excluded from the history. At that point, the history does not have the modification of that last action.
If I do an action that copies that part of the sate (in the right reducer), the state is fine. If I do an action that touches only another reducer, it will still be wrong.
So when I press undo, I undo to the wrong state. But if I get that action to mutate the state, then it's always valid.
Can a lib like redux-saga help me? I admit I have not read its
documentation since I am not making "real" API calls and I don't want
to have an overkill solution.
Redux-saga allows to perform custom side effects and introduce process manager since it has own event loop. Applying to original task, saga can help with splitting action with request and response in time.
Typical use case is emitting action with postfix _REQUEST, like LOAD_IMAGE_REQUEST, which intercepts with saga manager and does not pass into reducers. Then after async operation is done, saga emits _SUCCESS or _FAILURE-like action, dependent on sucessfullity of operation. That actions passed into store and applied with reducers.
Also, there is ideology called optimistic update. In that case _REQUEST event passed into store, but if action is failed, saga sents compensating event, which rollback optimistic action
I'm wondering what is the best way to implement CRUD operations in React Redux in case of List of entities.
Requirements:
1. Every row contain an entity
2. Changing a value in a text input trigger a PUT call to BE
3. Every row has Delete operation trigger a DELETE call to BE
4. Form has an ADD action trigger a POST call to BE
Notes:
1. No single Submit button
I thought about Redux Form for that but since I don't have a single submit operation I find it less appropriate (Feel free to correct me)
You can use Redux Form for that. If you setup a validator for the form, you can define if a field is dependent on another. Redux Form will run this validator for each change in any field.
You can setup something like Redux Observable or Redux Thunk to submit the form on Redux Form's CHANGE action when there are no validation errors in the form.
This way, you will submit the form on change, only if all the related fields are also filled.
I'm new to Redux. This is how I would do it. I will keep a state in the reducer which is called "personList". I will put all components in a container and map the personList to a property of the container called "propPersonList". When I create the ListItemComponent, I would also pass the index of the person in the list to the component as a property "propIndex". The onChange handler of the two inputs will dispatch an action with payload {index: this.props.propIndex, value: event.target.value}, then trigger a PUT request to backend (use lodash module to throttle it instead of triggering it everytime the input changes). The reducer will take care of the actions and update the state according to the payload. The add button will dispatch another action and the reducer will simply add an empty entity to the state, then trigger a request to the backend. The remove button will dispatch an action with the index as the payload, and the reducer will remove the corresponding entity from the list.
I feel like subtitling this question "Does Fluxxor want my application to work?". No doubt however I have not grasped how to co-operate with Fluxxor...
The error is:
Cannot dispatch an action ('NEXT_AJAX_REQUEST_IS_ABOUT_TO_BE_MADE') while another action ('FIRST_AJAX_REQUEST_IS_RETURNED') is being dispatched
Component A is the owner of Component B
Component A calls an action creator in its componentWillReceiveProps. This action creator makes an AJAX request. If successful we dispatch FIRST_AJAX_REQUEST_IS_RETURNED with some data into a store. The store updates. It emits change. Component A is listening for this change. Component A updates its state. Component A re-renders passing this state as props to Component B. Component B in its componentWillReceiveProps calls an action creator to make a second AJAX request based on the data it now has. Before the actual AJAX request is made the action creator dispatches NEXT_AJAX_REQUEST_IS_ABOUT_TO_BE_MADE - in order to put a store into a certain state.
I get the message about dispatching one action while another is in progress it seems because Fluxxor does not consider the first action complete - even though I cannot have made the second until the AJAX request was completed and I have the data. The issue seems to be calling the second action from the componentWillReceiveProps method of a child component in response to changes in the owner component's state arising from the first action.
So. I tried moving the second action to the success 'callback' in the first store. I still get the same message. Even if this was the right thing to do...
The second action depends on data contained in the first action. I cannot merge these two into one single request/action and then update 2 stores using waitFor.
http://fluxxor.com/guides/react.html#batched-updates
This fixed it.
However I do not understand why and would really appreciate an explanation if anyone has it.
I think that the effect is that Component A will not re-render until state changes arising from getStateFromFlux have fully completed. So that when Component B calls its action creator we are now fully done with the first action.
Is this approximately correct?
I have a Calendar component which, when rendered with a certain prop called LoadOnMount needs to call the server to load a set of flights.
The problem is that I update the calendar by listening to the CalendarStore's Events.UPDATE event, which is triggered by the UPDATE_CALENDAR action dispatched by my Dispatcher, and I load the set of flights using another action called LOAD_FLIGHT_LIST. So when I invoke this new action from the Calendar component's ComponentDidMount function I get the cannot dispatch in the middle of a dispatch error.
Any way to handle these sorts of dependencies? (The calendar is also fetched from the server)
You have two issues that I can identify:
The first is that you are trying to get the dispatcher to dispatch during a dispatch. That's not the way you should be doing it.
The second is that you seem to be performing AJAX/async calls from inside your dispatch handler. I don't want to say that you should never do that, but that does not seem to be necessary in your application.
Here's a link to another stack overflow question that I think is similar: https://stackoverflow.com/a/23637463/2152216
The difference is that the asker is trying to perform an Ajax call from within his dispatch handler, while you seem to be trying to dispatch an event that will in turn trigger an ajax call during the event's handling.
What you can do is create an action that asynchronously loads the flight list, then dispatch the FLIGHT_LIST_LOADED action afterwards passing it the fetched flight list. Your store should handle this action and broadcast a change event for all the component observers.
I hope you understand what I'm talking about. If you think I misunderstood your problem, let me know.