I'm using Redux Promise Middleware and my action creator returns an action with a promise.
Now, in the reducer, I receive the resolved promise data and I have to 'provide' the new state. I also have to do something that is not 'pure' with that data, e.g., store it in local storage.
How should I approach this situation and still keep the reducer pure? That data is obtained in middleware and the first time I get it is in reducer.
I know I can handle the promise in my action creator and access the data before dispatching the action but is there another better way?
You can create your own middleware!
You can call it localStorage-middleware for instance and you can dispatch the action before providing your data to the reducer. Your middleware will listen to that action, like dispatch(saveDataToLocalStorage(dataToSave))
Related
I am building application in nodejs where I have to display the data by hitting the HTTPS endpoint. I am using Swagger UI to display the data.
If this is the built in HttpService in NestJS, the service returns an RxJS Observable which by default is not awaitable. You can tack on a toPromise() to convert the Observble to a promise that can be awaited and should have the awaited response from there. Otherwise, you can remove the await and make the function non-async, returning the observable and letting NestJS subscribe to it under the hood.
Important side note: You'll need to make sure that you don't try to send back the raw Axios response, as there are circular references that Nest will not e able to stringify. Look into the observable pipe and map operators, or use a then after the toPromise() and map the response that way
If you are not required to user HttpService from NestJs, you can use request-promise-native or request-promise. These packages will return Promises by default and you can await them.
Hope it helps!
Redux-saga middleware gives us the feeling as if it runs on a separate thread. When it is told to wait for a certain action to be dispatched by the saga(generator function), it suspends the saga until the action of interest is dispatched. Single js runtime is single threaded, how saga middleware waits for an action to be dispatched and at the same time not block everything else?
Waiting for actions works like this:
For any take() effect redux-saga middleware makes an entry in takers array. An entry contains the pattern and the suspended generator.
On any action dispatch the middleware checks the action against the takers array. Matching generators are scheduled to be run.
This is asynchronous waiting that doesn't involve blocking anything.
I am working on a WebSocket application that uses React/Redux stack with Sage as the side-effects handler. Saga dispatches events on incoming WebSocket messages and specific slice reducers either
1. Handle the message and update the state
2. Reply to Websocket message immediately - based on the current state
3. Raise an error - Invalid message
I would like to contain the business logic in reducers, hence would like the reducers to raise WebSocket send events or set an error state, rather than splitting these 2 to Saga handler. Strategy I am looking at is to have global states state.outgoingMessages and state.errors where any slice reducer can set these states. If an outgoingMessage is set the sage middleware would on resumption would write back to the WebSocket, if an error state is set an Error Component would render this.
I don't think I am violating any reducer/saga rules, however I have the dilemma of passing down a common state to reducers. There being quite a bit of discussion around this topic
https://redux.js.org/docs/recipes/reducers/BeyondCombineReducers.html#sharing-data-between-slice-reducers
provides a recipe of passing down additional sate. I can have a higher order reducer and pass down additional states outgoingMessages and error to slice reducers, would this be an anit-pattern, or is there a better way to handle the problem altogether?
I have the following middleware.
this middleware acts like the redux-thunk middleware, but passing the dispatcher and the state getter to the action creator function, but also I pass the next middleware that can be called. in this case I can export all my middlewares like this
so In my action creator, instead of dispatching the action, I just pass it to the next middleware.
I just want to know why I should use redux-thunk instead of this simple customThunk middleware?
I'm building an library with Redux that involves using a timer. I have an action creator that dispatches a START_TIMER event and should also should also call start on a timer object. The code looks like this:
// thunk action creator
const startTimer = () => (dispatch, getState) => {
if (!getState().timer.isRunning)
externalTimerObject.start()
dispatch({
type: 'START_TIMER'
})
}
There are two issues I'm trying to solve:
If I want to log my actions to a database or localStorage so that I can replay them to get to a consistent app state then even if rootState.timer.isRunning is true, my timer object will not be running.
The conditional if (!getState().timer.isRunning) requires that I know where in the root state timer is mounted. Since I'm building this as a library, I can't assume that timer is always going to be mounted directly onto the root state.
If I want to log my actions to a database or localStorage so that I can replay them to get to a consistent app state then even if rootState.timer.isRunning is true, my timer object will not be running.
I think that this is actually correct by design. When you reproduce a recorded log, you want everything to happen exactly as it happened before in terms of the produced actions.
For example, rather than fire off the real AJAX requests from your computer, while replaying actions, you’ll probably want to replay the recorded AJAX responses that were dispatched during that user session in the past.
I think timer falls into the same category: from the Redux point of view, action history describes what happened “as a result” of side effects, and replaying the actions should be enough to get your app into the same state even if those side effects did not actually fire again.
The conditional if (!getState().timer.isRunning) requires that I know where in the root state timer is mounted. Since I'm building this as a library, I can't assume that timer is always going to be mounted directly onto the root state.
If you’re building a library, you also probably shouldn’t depend on the thunk middleware being available. It seems like you depend on it in your action creator. It is hard to say more without understanding your exact use case.