MaximeBernard on github-actions
chore(ci): setup github actions (compare)
evertbouw on master
docs(README): Fix mis-typo in T… Merge pull request #745 from na… (compare)
jayphelps on master
docs(README): Adds note about 2… (compare)
jayphelps on disclaimer
docs(README): Adds note about 2… (compare)
jayphelps on peers
fix(package.json): Allow all ve… (compare)
jayphelps on gh-pages
update book update book (compare)
@PogoniiA The answer in that StackOverflow link is correct.
Because Firebase doesn't have a native RxJS implementation, you need to take their streaming function, wrap it in an RxJS observable, and pipe off that in Redux-Observable.
From there, it just dispatches actions and the rest of your code works as you'd expect.
Hello guys,
I'm trying to test my Epic, I'm quite new with TestScheduler and Marble Diagrams.
I hope someone can help.
this is my Epic:
const deleteMediaEpic: Epic = (actions$, state$: StateObservable, { api }: EpicDependencies) =>
actions$.pipe(
ofType(DELETE_MEDIA),
switchMap((action: DeleteMediaAction) => api.deleteMedia(action.payload.operationCode, action.payload.productKey, action.payload.mediaToDelete).pipe(
switchMap(() => {
const actionsToDispatch = []
actionsToDispatch.push(productSelected(action.payload.productKey, action.payload.operationCode))
actionsToDispatch.push(clearMediaSelected([]))
return of(...actionsToDispatch)
}),
catchError(mediaFetchError => of(`Error in deleteMediasEpic: ${mediaFetchError}`))
))
)
and this is my test:
it('Delete select Media', () => {
testScheduler.run(({ hot, cold, expectObservable }) => {
const action$ = hot('-a', {
a: { type: 'DELETE_MEDIA', payload: { productKey: 'PRODUCT_KEY1', operationCode: 'VPV_H_SHANAOR1', mediaToDelete: [0] } }
})
const state$ = {}
const dependencies = {
getJSON: url => cold('--a', {
a: { url }
})
}
const output$ = deleteMediaEpic(action$, state$, dependencies)
expectObservable(output$).toBe('---bc', {
b: {
type: 'PRODUCT_SELECTED',
payload: { productKey: 'PRODUCT_KEY1', saleCode: 'VPV_H_SHANAOR1', filtersType: undefined }
},
c: {
type: 'CLEAR_MEDIA_SELECTED',
payload: {
defaultValue: []
}
}
})
})
})
for me of
is a sequence operator and c should be immediately after b.
Hope you can understand something from the code me.
and this is the result of the test:
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
@@ -1,8 +1,8 @@
Array [
Object {
- "frame": 3,
+ "frame": 6,
"notification": Notification {
"error": undefined,
"hasValue": true,
"kind": "N",
"value": Object {
@@ -14,11 +14,11 @@
"type": "PRODUCT_SELECTED",
},
},
},
Object {
- "frame": 4,
+ "frame": 6,
"notification": Notification {
"error": undefined,
"hasValue": true,
"kind": "N",
"value": Object {
5 |
6 | const testScheduler = new TestScheduler(
> 7 | (actual, expected) => { expect(actual).toEqual(expected) }
| ^
8 | )
@ThomasEddie
I've been battling with redux-observable and typescript for a couple of hours now and I'm finally up and running.
I strongly suggest using redux-toolkit if you haven't done so before. https://redux-toolkit.js.org/
They have a very small example here: https://redux-toolkit.js.org/api/createAction#with-redux-observable
This is what worked for me, but I've been using redux-toolkit for a couple of projects now so this step was pretty natural I guess.
Before getting that working I mucked about with typesafe-actions since that was what examples I found was using. It was type-hell. From my short hours of that, I suggest not having typesafe-actions and redux-toolkit in the same project. They want to do the same thing.
I also had a look at this example repo: https://github.com/mitsuruog/react-redux-observable-typescript-sample
which does redux-observable with typesafe-actions. Looks very decent. The import * as actions from '...' thing here https://github.com/mitsuruog/react-redux-observable-typescript-sample/blob/master/src/shared/store/index.ts#L6
forces you to split your actions to its own file with nothing else in them, which is a good habit to have.
Here's my redux store setup for inspiration:
import {combineReducers, configureStore, Action, createAction} from "@reduxjs/toolkit";
import { combineEpics, createEpicMiddleware } from "redux-observable";
import { filter, map } from "rxjs/operators";
import { Observable } from "rxjs";
export const ping = createAction<{ foo: string }>("ping");
export const pong = createAction<{ bar: string }>("pong");
const epicMiddleware = createEpicMiddleware();
const epic1 = (action$: Observable<Action>) =>
action$.pipe(
filter(ping.match),
map((a) => pong({ bar: a.payload.foo.toUpperCase() }))
);
const rootEpic = combineEpics(epic1);
const rootReducer = combineReducers({
// your reducers
});
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(epicMiddleware),
});
epicMiddleware.run(rootEpic);
export type RootState = ReturnType<typeof rootReducer>;
Probably this is not the right place to ask such an off-topic question - but I'm wondering is Redux Observable still a popular choice among developers?
I personally like it quite much, but perhaps now there are some better alternatives. I see people keep using redux-sagas - but I personally can't really stand them.
And some avoid redux in the first place, therefore use just hook libraries such as https://www.npmjs.com/package/rxjs-hooks
Just curios to hear some opinions about some popular options post redux-observable
@jzarzeckis Great question! One I've pondered myself since I started using it. RecoilJS argument at the bottom.
Redux-Observable is very niche in terms of who's using it, but it brings an amazing amount of value to a project. I will absolutely use it on any project I write myself and just got my place of employment to start using it. The biggest complaint is the lack of documentation (for it an RxJS) whereas I've heard how much simpler the epic model has been. We could achieve the same thing writing custom middleware, but it wouldn't be in these slick functional pipelines that RxJS provides.
Redux-Observable is Message-Oriented Programming. This is by-far, one of the best ways to build projects. If you look at engineers that work on backend services, they're going more and more for a distributed model of micro services with an event bus and a standard interface between machines. It's not just machines talking to machines, there's usually a broker somewhere like RabbitMQ, Redis, or Kafka in the middle handling the publishing and subscribing of micro services to the services they care about. Sound familiar? It's the same as ofType
in Redux-Observable.
Many developers get bored with old tech (myself included). The reason React is still in vogue happens to be because the component API fundamentally changes ever year. People have to keep making tutorial videos, writing articles, and complaining about it. It sells itself. Svelte would've taken over if not for hooks as it's a lot easier to understand and works on the same observable model as hooks.
Redux has been falling out of favor because React hooks are more convenient the same way imperative code is right there in the language and RxJS is not. Sadly, React hooks are messy, impossible to unit test unless you pull them into a separate hook, and easy to wind up with serious performance problems (one reason why RecoilJS exists). There are other reasons like Redux is falling out of favor, but I attribute it to the fact that nothing really changes; therefore, no one really talks about it. Where I work, we decided to keep using Redux going forward and are even using it more now; although, we don't agree with the single-store model and have changed that methodology too.
The reason RecoilJS isn't a replacement for Redux-Observable is because it doesn't have a single event bus. Every observable or atom is watching other observables for changes. If you've ever written an RxJS application without Redux-Observable, you probably know how complicated this can be. It won't take long for people to have no clue what the business logic is doing. Having a single event bus (Redux) makes everything easier at a small potential cost to performance.
On top of that, RecoilJS is like writing Redux middleware without RxJS. It uses its own observable model and is ultimately just a way around React Context API. Heck, we had the same issue with React's context at work on multiple occasions. We even built our own form library to handle it.
Hi Everyone, I have a question regarding RXJS and Redux Obs.
I would like to make the epic for fetching data when user comes to /public/:id
then if user leave and data comes later for next time user go in the same path(different id) user still see the last then loading
So my questing do I need to use Cancellation
on switchmap ? because I have tried and after user go in the same path it’s not fetching anymore.
@nuttikung switchMap
has automatic cancelation in some ways. If it receives the command twice, the first one gets canceled. Or do you mean something like take
or takeUntil
on your data fetch?
I write in cancelation for all my data fetching, but it's different for each based on the needs of the app. For instance, if the user logs in, does it fire the action again? If so, switchMap
is enough. If not, you have to write that in yourself.
Hi could someone help me with this : I'm getting an error "no reducer provider for key "somekey" ". I tried many different way of importing and exporting, and this only happens when I run the store using Jest and Enzyme. The code : I'm exporting the reducer like so: export default function connections(state = DEFAULT, action = {}) Then I'm importing like so:
import { connections } from '../redux/modules/connections'; Then I'm using combineReducers: import { combineReducers } from 'redux';
const appReducer = combineReducers({
connections,
}); And them I'm creating the store: function rootReducer(state, action) {
let finalState = appReducer(state, action);
return finalState;
}
const storeGenerator = (initialState) => {
const epicMiddleware = createEpicMiddleware();
let middlewares = applyMiddleware(epicMiddleware);
if (blabla...) {
// additional logging middlewares when running the application in development mode
middlewares = applyMiddleware(epicMiddleware, logger);
}
const store = createStore(rootReducer, initialState, composeWithDevTools(middlewares));
epicMiddleware.run(rootEpic);
return store;
}
export default storeGenerator;
catchError
wrapper, but without explicit dispatch, it might not work the way you expect in every use case. I have an article about explicit dispatch here: https://itnext.io/the-best-practice-anti-pattern-5e8bd873aadf
@jsjow First, your issue is not with Redux-Observable.
It's most-likely a bad reducer import. Something like reducer
instead of { reducer }
.
Lastly, you when posting code samples, you should use triple backticks to ensure the code is readable.
What you pasted was a bunch of plaintext with no tabbing or syntax highlighting; meaning, it was more difficult to parse. I've seen many people here help others when they paste code in a way that's easily readable.