For this effect,
#Effect()
triggerOtherAction$: Observable<Action> = this.actions$
.ofType(SOME_ACTION)
.do(() => console.log("This line works for both"))
.map(() => new OtherAction())
When I dispatch an action, I can think these two ways
first,
Observable.of(new SomeAction()).subscribe(this.store);
second,
this.store.dispatch(new SomeAction());
what is the difference between above two lines? For the first one, it doesn't trigger other action, but execute the line of do() and reducer works well.
There is no reason to dispatch actions using code like this:
Observable.of(new SomeAction()).subscribe(this.store);
In fact, there is a good reason not to: the observable to which the store is subscribing will complete and that will see the store complete, too.
In version 2.2.1 of #ngrx/store, that's not a problem - as its implementation of complete does nothing - but with the current master, complete is implemented and dispatching an action as above will see the store complete and no further actions will be dispatched.
Related
So I am new to "rxjs" and redux-observables (worked with redux-saga before and familiar with the concept of reactive programming).
What I want to know is how can I dispatch an action from an epic, wait for that action to complete and after that keep doing things in the epic, based on the new state that I've got after the action completion.
I will describe my current situation and hopefully it will help:
export const cartValidationEpic = (action$, state$) =>
action$.pipe(
ofType(Actions.CART_VALIDATION_REQUESTED),
mapTo(action(Actions.CART_REFRESH_REQUESTED)),
takeUntil(action$.pipe(ofType(Actions.CART_SYNC_RECEIVED))),
withLatestFrom(state$),
map(([, updatedState]) => selectCart(updatedState))
updatedCart => validate(updatedCart)
)
I'm working on an e-commerce web app, and I want to validate the cart before checkout.
I want that the cartValidationEpic will listen to "CART_VALIDATION_REQUESTED",
then dispatch an action "CART_REFRESH_REQUESTED" in order to get the updated cart,
and I want to make sure that the epic will run the validation function only after the state updated with the updated cart.
Currently while I'm running the app and clicking on the button that trigger the dispatch of "CART_VALIDATION_REQUESTED", all I can see in redux devtools is that the "CART_VALIDATION_REQUESTED" action was dispatched, but nothing dispatched after it.
I wonder what I am missing and if I am in the right direction of solving it.
Thanks for your help.
I'm trying to do a simple notification system with redux-observable. I'm new to rxjs so I'm having a hard time doing it.
What I'm trying to do is:
Dispatch an intent to display a notification
Detect the intent with an Epic
Dispatch the action that inserts the new notification
Wait 3 seconds
Dispatch another action that deletes the old notification
This is my Epic:
import { NOTIFICATION_DISPLAY_REQUESTED } from '../actions/actionTypes';
import { displayNotification, hideNotification } from '../actions/notifications';
export const requestNotificationEpic = (action$, store) =>
action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
.mapTo(displayNotification(action$.notification))
.delay(3000)
.mapTo(hideNotification(action$.notification));
What really happens is that NOTIFICATION_DISPLAY_REQUESTED is dispatched, and 3 seconds later, hideNotification is dispatched. displayNotification never happens.
I could just dispatch displayNotification from the view, delay 3 seconds and then dispatch hideNotification. But later I want to delete the last notification before adding a new one if there are more than 3 active notifications. That's why I dispatch displayNotification manually from inside the epic in this simple case.
So, how do I achieve this? Sorry if this is super simple question, I'm just new to all this and need some help.
Note: I know redux-saga exists, is just that redux-obsevable made more sense to me.
If you're new to RxJS, this isn't so simple :)
Couple things up front:
Operator chains
An Epic is a function which takes a stream of actions and returns a stream of actions. Actions in, actions out. The functions you chain to transform matching actions are called operators. Chaining operators is a lot like chaining garden hoses or power cords--the values flow from one to the other. It's also very similar to just chaining regular functions like third(second(first())) except that Observables have an additional dimension of time, so the operators are applied on each value that flows through them.
So if you say stream.mapTo(x).mapTo(y) the fact that you firsted mapped to x is made meaningless when you .mapTo(y) since mapTo ignores the source's values and instead just maps it to the one provided.
If instead you used map, it might become more apparant:
stream.map(value => 'a message').map(message => message + '!!!')
Just to be claer, this chaining of operators stuff is RxJS, not specific to redux-observable, which is more a pattern of using idiomatic RxJS with a tiny amount of glue into redux.
action$ is an Observable (technically ActionsObservable)
The argument action$ is an Observable of actions, not an actual action itself. So action$.notification will be undefined. That's one of the reasons people commonly use the dollar sign suffix, to denote it is a stream of those things.
Consider only have 2 actions, not 3
Your example shows you using three actions NOTIFICATION_DISPLAY_REQUESTED and two others to show and hide the notifications. In this case, the original intent action is basically the same as displayNotification() because it would be dispatched synchronously after the other.
Consider only have two actions, one for "show this notification" and another for "hide this notification". While this isn't a rule, it can often simplify your code and increase performance since your reducers don't have to run twice.
This is what it would look like in your case (name things however you'd like, of course):
export const displayNotificationEpic = (action$, store) =>
action$.ofType(DISPLAY_NOTIFICATION)
.delay(3000)
.map(action => hideNotification(action.notification));
// UI code kicks it off some how...
store.dispatch(displayNotification('hello world'));
Your reducers would then receive DISPLAY_NOTIFICATION and then 3 seconds later HIDE_NOTIFICATION (order whatever).
Also, cruicial to remember rom the redux-observable docs:
REMEMBER: Epics run alongside the normal Redux dispatch channel, after the reducers have already received them. When you map an action to another one, you are not preventing the original action from reaching the reducers; that action has already been through them!
Solution
Although I suggest using only two actions in this case (see above), I do want to directly answer your question! Since RxJS is a very flexible library there are many ways of accomplishing what you're asking for.
Here a couple:
One epic, using concat
The concat operator is used subscribe to all the provided Observables one at a time, moving onto the next one only when the current one completes. It "drains" each Observable one at a time.
If we wanted to create a stream that emits one action, waits 3000 ms then emits a different one, you could do this:
Observable.of(displayNotification(action.notification))
.concat(
Observable.of(hideNotification(action.notification))
.delay(3000)
)
Or this:
Observable.concat(
Observable.of(displayNotification(action.notification)),
Observable.of(hideNotification(action.notification))
.delay(3000)
)
In this case, they have the exact same effect. The key is that we are applying the delay to different Observable than the first--because we only want to delay the second action. We isolate them.
To use inside your epic, you'll need a merging strategy operator like mergeMap, switchMap, etc. These are very important to learn well as they're used very often in RxJS.
export const requestNotificationEpic = (action$, store) =>
action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
.mergeMap(action =>
Observable.concat(
Observable.of(displayNotification(action.notification)),
Observable.of(hideNotification(action.notification))
.delay(3000)
)
);
Two different epics
Another way of doing this would be to create two different epics. One is responsible for maping the first second to the second, the other for waiting 3 seconds before hiding.
export const requestNotificationEpic = (action$, store) =>
action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
.map(action => displayNotification(action.notification));
export const displayNotificationEpic = (action$, store) =>
action$.ofType(DISPLAY_NOTIFICATION)
.delay(3000)
.map(action => hideNotification(action.notification));
This works because epics can match against all actions, even ones that other epics have emitted! This allows clean separation, composition, and testing.
This example (to me) better demonstrates that having two intent actions is unneccesary for this example, but there may be requirements you didn't provide that justify it.
If this was very confusing, I would recommend diving deep into RxJS first. Tutorials, videos, workshops, etc. This is only skimming the surface, it gets much much deeper, but the payout is great for most people who stick with it.
Maybe I'm thinking about this wrong, but a common pattern I use with redux-thunk is to return a promise so I can perform some additional actions in the container object when something completes or fails.
Using Thunk as an example:
Action Creator:
const action = ({ data }) => (dispatch) =>
fetch(`some http url`)
.then(response => {
if(response.ok) {
return response.json();
}
return Promise.reject(response);
})
Somewhere in the connected component:
this.props.action("Some Data")
.then(console.log)
.catch(error => console.error("ERROR"));
Is there a clean way of doing something similar in Redux-Observable/Rxjs? Basically returning a promise from an action, calling an epic, that returns resolve or reject once the observable is complete.
Generally speaking, I try to shy people away from these patterns when using things like redux-observable/redux-saga. Instead, if you're waiting for an action you dispatched to update the store's state, rely on that state update itself or some sort of transactional metadata your reducers store in the state about it. e.g. { transactions: { "123": { isPending: true, error: null } }
However, if you really do want to do it, you can write (or use an existing) middleware that returns a Promise from dispatch that will resolve when some other specified action has been dispatched (presumably by your epics). redux-wait-for-action is one example (not a recommendation, though cause I haven't used any)
Keep in mind that Promises are not normally cancellable, so you could accidentally create a situation where a component starts waiting for an action, the user leaves that page and the component is unmounted, and you're still waiting for that other action--which can cause weirdness later, like if they come back to that page, etc.
If you're waiting to chain side effects, that belongs in your epics. Kick off a single action that an epic listens for, makes the side effect, then it emits another action to signal completion. Another epic listens for that completion action and then begins the other side effect, etc. You could put them all in a single monolithic epic, if you want, but I find the separation easier for testing and reuse.
Project (Todolist) was created with immutable library, source here
Store structure: project have many tasks, In redux store: State - map, projects, tasks - Records
When I asyncly remove project ...
export const removeProject = project => (dispatch) => {
if (!isProjectExist(project)) return Promise.resolve()
return projectService
.delete(project)
.then(
() => {
dispatch(remove(project))
console.log("post removeProject resolved")
},
handleError,
)
}
.... that was created after initialization - it will be deleted and properly unmounted, but when project was passed as initialState - ProjectList will not be rerendered, and ProjectItem try to render itself with stale data, and fail, as in picture
It have tests
It looks like reducer returs changed data, but I use immutablejs, and previously i use normalizr-immutable, but I thought that source of issue in this library and write my own normalizeInitialState (source), it did not help, now I think that maybe source of problem in redux-immutable
I struggled entire day on solving of this problem
creator of redux says
I don't think this is something we can fix. React state changes are
asynchronous and React may (or may not) batch them. Therefore, the
moment you press “Remove”, the Redux store updates, and both Item and
App receive the new state. Even if the App state change results in
unmounting of Items, that will happen later than mapStateToProps is
called for Item.
Unless I'm mistaken, there is nothing we can do. You have two options:
Request all required state at App (or a lower, e.g. ItemList) level
and pass it down to “dumb” Items. Add safeguards to mapStateToProps
for “currently unmounting” state. For example, you may return null
from render in this case. Potentially we could have the component
generated by connect() return null from its render if mapStateToProps
returned null. Does this make any sense? Is this too surprising?
Hm, I never saw stubs like return (<div></div>) or safeguards in mapStateToProps in others code
markerikson
I'm not entirely sure I follow what exactly your problem is, but as a
guess: it sounds like the child component is re-rendering before the
parent is. This is a known issue with React-Redux v4 and earlier. The
v5 beta fixes that issue. Try installing react-redux#next and see if
that takes care of your problem.
I would like many different redux actions in my app to all trigger common functionality in a specific reducer. I would like to avoid having to either repeat some flag in every action creator (like doThing: true) that the reducer looks for. I also don't want to have to have the reducer just look for every individual action that falls into this category, since that also requires someone to remember to do this every time they add a new action, like adding the flag.
I was thinking of dispatching a second action every time one of these actions is going to be dispatched. This would not be hard to do, but I'd rather not have 2 actions dispatched every time one thing happens. It seems like it would pollute the state history.
Is there a common way of solving this problem?
For more context to my specific problem, the specific feature is related to the API client my app uses to talk to our API. On every successful response, we'd like to do something in a reducer to update the state, and on every failed response, we'd like to do something else.
There are many different success and failure actions (such as ITEM_FETCH_SUCCESS or WIDGET_UPDATE_FAILURE), and adding a flag to all of them would be hard to remember to do when new ones are added.
Since all api requests go through a single function, that function COULD dispatch generic REQUEST_SUCCESS and REQUEST_FAILURE actions. But this would mean every response from the server would dispatch 2 actions (REQUEST_SUCCESS and ITEM_FETCH_SUCCESS). This is obviously not ideal since it would mean many more actions in my state history.
Assuming the generic REQUEST_SUCCESS and REQUEST_FAILURE actions are updating their own specific portions of the state-tree then it is fine to dispatch them as distinct actions. Doing this does not necessarily imply the pollution of your state history but can simply be a better description of the app's intentions.
ITEM_FETCH_SUCCESS: Change state for item
REQUEST_SUCCESS: Change state for request
WIDGET_UPDATE_FAILURE: Change state for widget
REQUEST_FAILURE: Change state for request
You can see that whilst the actions are intimately related, they are not necessarily the same thing as they change different parts of the state tree.
Accepting this, the question is: How best to implement the action-pairs so that adding new actions does not mean remembering to add its corresponding REQUEST_* partner?
I would consider applying a simple redux middleware component. This could intercept the return from your api and dispatch the appropriate REQUEST_* action automatically.
Here is an example from some live code. This middleware intercepts a disconnect event raised by a websocket and automatically dispatches a custom action as a result. It at least shows the principle:
//Dispatch a disconnect action when the websocket disconnects
//This is the custom action provided by the middleware
import io from 'socket.io-client'
import { actions } from './action'
const websocket = ({ websocketUrl }) => store => {
const socket = io(websocketUrl)
socket.on('disconnect', () => store.dispatch(actions.disconnect()))
}
export default websocket
//Apply the custom middleware via the redux createStore function
//Also include the thunk middleware because it is useful
import { applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import websocket from './middleware'
function websocketize (opts) {
return createStore => (reducers, initial, enhancer) => {
const middleware = applyMiddleware(thunk, websocket(opts))
return createStore(reducers, initial, middleware)
}
}
export default websocketize
// Create the top-level redux store passing in the custom middleware enhancer
const opts = {websocketUrl: env.WEBSOCKET_URL}
const store = createStore(reducers, websocketize(opts))
This implementation keeps everything inside your reducers as opposed to having logic outside in an interception(middleware). Both ways are valid.
Try a sub-reducer pattern. I usually feel gross when I see it used(because it is usually used wrong), but your situation sounds perfect.
Extract duplicate functionality out of your reducers to one single
sub-reducer.
Then pass that reducer as a function to all others that need it.
Then pass the action and state onto the sub-reducer.
The sub-reducer does it's thing and returns that slice of state to
your parent reducer to allow you to do whatever you want with it
there (ie return it, mutate some more, some logic).
Also if you are tired of worrying about typing out "all the stuff" for async then I highly recommend you try out redux-crud.js
It also is possible and a simple way to do that would be to give every action to one reducer and let it do that common mutation, in a single case:
case actionOne
actionTwo
actionThree
actionFour: {
//do common stuff here
}
. But you said it is not duplicated, it is similar, which means your case becomes complicated by branching logic. I also don't recommend this. Keep cases simple so you can easily catch invalid mutations. This should be a super power of redux that it is easy to catch mutation errors. And for this reason and many others I don't recommend normalizing data in the front end.