redux-observable / redux-observable

RxJS middleware for action side effects in Redux using "Epics"
https://redux-observable.js.org
MIT License
7.85k stars 466 forks source link

Add more recipes #87

Open jayphelps opened 8 years ago

jayphelps commented 8 years ago

Everyone,

Let's add a bunch of thoughts here about Recipes people would like to see added to the docs. If you can, please feel free to just go ahead and PR any you think of or that are on this list! 🚀

gusvargas commented 8 years ago

Do you think these examples should be view library/framework agnostic? For example, should the router navigation examples actually use react(-router)?(-redux)? or do you imagine that we'd just simulate routing related actions similar to what react-redux-router#push may generate while showcasing interesting epics.

jayphelps commented 8 years ago

Both 😄

I think it's important to try and keep things unbiased and present the general patterns that should apply to all frameworks. But because there will be subtleties in the real world so we should also try and provide specific examples for at least the three or four frameworks too (like react-router requiring some integration with redux)

winkerVSbecks commented 8 years ago

@jayphelps It might be helpful to add a polling recipe. Is this the best approach or can you recommend something better? https://jsbin.com/bupeja/52/edit?js,output

jayphelps commented 8 years ago

@winkerVSbecks polling is a great recipe! I would recommend placing the ajax stuff inside the first switchMap so that it has access to the original action.payload:

https://jsbin.com/xiwasu/edit?js,output

I'm thinking the recipe for that should prolly be a different use case than fetching a user. Maybe something like logging or checking internet connection.

Timopheym commented 8 years ago

I'll be glad to see one about websocket streams support... ;)

murraybauer commented 8 years ago

@jayphelps fetching a 'newsfeed' could be a good example

cloud-walker commented 8 years ago

For the polling example I suggest using exhaustMap instead of mergeMap to ensure promise resolve

jayphelps commented 8 years ago

@cloud-walker care to elaborate? As an aside, I don't recommend using promises for these sorts of situations unless you have no control over the originating API--because Promises aren't cancellable and aren't lazy.

cloud-walker commented 8 years ago

I've made an example without promises, to clarify my point.

In my project I need to poll for an endpoint that may not have the results immediately, so we (for now) make use of limit and offset to track the state of the polling, so I've to know the response of the current request before continue the polling.

griffinmichl commented 7 years ago

Currently working on integrating redux-observable into an app that uses react-router-redux and redux-form. Once I've got the patterns nailed down, I'd love to contribute some recipes. react-router-redux is pretty straightforward, but I'm still working out redux-form.

mattiaocchiuto commented 7 years ago

Hi, I've used redux-observable to integrate my app with pusherjs, do you think it could be a good recipe to add? Of course I could also write it with a difference service from pusherjs if you prefer.

SamMatthewsIsACommonName commented 7 years ago

I've made a 'recipe' (kind of I think...) for a combined navigate to page and then scroll to section approach. I did this because most of the links on my home page scroll to content, but I was having issues with clicking those links from another page (obviously).. so I wanted to make the navigation process a bit more granular e.g navigate before trying to scroll. Some of it is probably quite backwards hence why I use the term 'recipe' lightly. In real world terms this would be like a grilled cheese level of 'recipe'. Also thanks for the help from @BerkeleyTrue on gitter
https://gist.github.com/sammy6464/42941788bef3cb4cf26962b69eba133b

MarkMurphy commented 7 years ago

This may be outside the scope of things here but personally I'd love to see examples of a declarative api service for ajax calls in epics. eg.

import api from '../../services/api';

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      api.users.fetch(action.payload.id)
        .map(response => fetchUserFulfilled(response))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );

More specifically, I'd like to see some docs that cover best practices (or at least some ideas) for building a client side api consumer when using redux-observable (maybe something along these lines?) I'm guessing doing ajax.getJSON('https://exmaple.com/:collection/:acton') all the time in your epics isn't how you guys do it at Netflix right? That might be fine for small apis or simple use cases but for larger apis that have things like versioning and authentication, doing things like passing custom headers, bearer tokens for authentication and sending post data etc., go against the don't repeat yourself principle.

In a project I worked on recently we used the normalizr module to transform all api responses from the server into something better suited to store in redux. Because the api service we built did this in it's own handler before passing back to the original caller (i.e. an async thunk action), we were able to keep normalizr transparent to the rest of the application.

jrmcdona commented 7 years ago

Does anybody have a good recipe for RxJs websocket call? Also, one that dispatch actions based on each event that comes through on the websocket?

lazyeasydev commented 7 years ago

@jrmcdona https://github.com/redux-observable/redux-observable/issues/260 casertap, at the bottom of that page, made a solid jsfiddle showing off using websockets.

To save you the clicks --> https://jsfiddle.net/rolele/ued0oh9q/

jayphelps commented 7 years ago

here's a working example of multiplexing a socket using a mock (aka fake) WebSocket server. If you don't need multiplexing, things are easier than this.

https://jsbin.com/rumese/edit?js,output

Enter whatever fake ticker symbols you want and add them e.g. image

It has a bunch of code that isn't really used, but might help you later--just take the time to understand it and whether you want it or not! e.g. the retryWhen, removing the tickers, etc.

jrmcdona commented 7 years ago

Thanks guys. I am not using multiplexing. I want to subscribe to my websocket and then I will dispatch some actions based on the events that are emitted via websocket. Something like this (although this doesn't work).

My socket$.subscribe function seems out of place here.

const socket$ = Observable.webSocket<DataEvent>(
  "ws://thewebsocketurl"
);

const bankStreamEpic = (action$, store) =>
  action$.ofType(START_BANK_STREAM).mergeMap(action => {
    console.log("in epic mergeMap");
    socket$
      .subscribe(
        e => {
          console.log("dispatch event " + e);
         distributeEvent(e);
        },
        e => {
          logger.log("AmbassadorsDataService", "Unclean socket closure");
        },
        () => {
          logger.log("AmbassadorsDataService", "Socket connection closed");
        }
      )
  });

   function distributeEvent(event: DataEvent) : void {
        //this.logger.log('AmbassadorsDataService', 'Event Received: ' + event.command + ' and id: ' + event.id);
        if(event.source === '/ambassadors/bank') {
            if( event.command === 'REMOVE') {
                removeDataEvent(event);
            }
            else if(event.command == 'ADD') {
                loadDataEvent(event);
            }
        }
    }

Thoughts on what I should be changing here?

jayphelps commented 7 years ago

@jrmcdona you wanna throw it up on StackOverflow?

jrmcdona commented 7 years ago

Good call @jayphelps done!

https://stackoverflow.com/questions/45069489/using-redux-observable-and-subscribing-to-a-websocket

AyWa commented 7 years ago

Hey everyone,

I just started to use redux-observable and learning rx. But for

Patterns with common libs like redux-form (related)

This is the patterns I did to return a promise: https://github.com/AyWa/redux-promise-observable it is like https://github.com/mhssmnn/redux-form-saga which is used for redux-sagas

As I just started to learn, it may not be that well design but it could be a pattern for all the package that require promises

ayleesedai commented 6 years ago

Hi everyone, I just started working on rxjs and redux-observable. I wrote a single epic to manage a websocket chat. It:

Here's the code... please, remember this is my first attempt with rx, don't cover me with too much insults! :D

import { Observable } from 'rxjs';
import { changeChatStatus, CHAT_STATUS_CONNECTED, CONNECT_CHAT, DISCONNECT_CHAT, getChatUser } from '../chat';
import { addMessage, SEND_MESSAGE } from '../messages';

const socket$ = Observable.webSocket(
    "ws://localhost:11235"
);

const webSockectMessageEpic = (action$, {getState}) =>
    action$
        .ofType(CONNECT_CHAT)
        .switchMap(() => 
            socket$
                .map(payload => addMessage(JSON.parse(payload)))
                .takeUntil(action$.ofType(DISCONNECT_CHAT))
                .startWith(changeChatStatus(CHAT_STATUS_CONNECTED, getChatUser(getState())))
                .merge(
                    action$
                        .ofType(SEND_MESSAGE)
                        .mergeMap(action => {
                            const mess = { ...action.payload, date: new Date().getTime() };
                            socket$.next(JSON.stringify(mess))
                            return Observable.empty();
                        })
                )
        );

export default webSockectMessageEpic;

I dunno if this code could be useful to someone else, but I would appreciate some feedbacks/critics/improvements, because I really like this reactive approach and wanna learn how to use it at its best.

(full example, client+server, here: https://github.com/react-genova/follows-up within le-chat-noir folder)

cdaringe commented 6 years ago

@jayphelps, i landed https://github.com/redux-observable/redux-observable/pull/490 to hopefully check off redux-form

jakesylvestre commented 6 years ago

+1 on including follow-up by @ayleesedai . Would this be possible?