by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Sep 28 07:56
    evertbouw locked #736
  • Sep 27 23:23
    jayphelps commented #736
  • Sep 27 20:11
    pawelotto commented #736
  • Sep 27 17:35
    jayphelps commented #736
  • Sep 27 17:12
    pawelotto commented #736
  • Sep 27 00:21
    Artizmo commented #736
  • Sep 26 14:53
    jayphelps commented #736
  • Sep 26 13:59
    jayphelps closed #736
  • Sep 26 13:59
    jayphelps commented #736
  • Sep 26 13:46
    pawelotto opened #736
  • Sep 23 15:33
    jayphelps commented #735
  • Sep 23 08:16
    evertbouw opened #735
  • Sep 18 11:15
    pbadenski commented #562
  • Sep 18 11:15
    pbadenski commented #562
  • Sep 18 11:15
    pbadenski commented #562
  • Sep 18 11:06
    pbadenski commented #562
  • Jul 24 16:02
    jun-sheaf commented #734
  • Jul 23 19:08
    jun-sheaf synchronize #734
  • Jul 23 19:07
    jun-sheaf synchronize #734
  • Jul 23 19:02
    jun-sheaf synchronize #734
Evert Bouw
@evertbouw
after that I don't think much needs to be done anymore
Kevin Ghadyani
@Sawtaytoes
There's a version 2?
Evert Bouw
@evertbouw
in alpha
it removes the ActionsObservable type
so you can no longer do action$.ofType("foo") but you have to do action$.pipe(ofType("foo"))
I doubt you can measure it but ofType should be faster as well
xavier7179
@xavier7179
@evertbouw so should we expect to do quite a work to make our v1 code to v2?
Evert Bouw
@evertbouw
if you are already using the pipe operator you don't need to change anything
at least so far, I don't know if we'll come up with more breaking changes
amir
@amirbr

Hey guys, I think to my self if there is a better way to take one epic that can handle with multi-action.
for example, I have an epic that is in charge of my module (is some page in my app). I use merge operator to do that, but I'm not sure if it can cause a performance problem.

I'm not sure I'm clear so I post an example below.

const merchEpic: Epic = (actions$, state$: StateObservable, { api }: EpicDependencies) => {
  const getNavigation$ = actions$.pipe(
    ofType(GET_NAVIGATION),
    switchMap...
  )

  const productFetched$ = actions$.pipe(
    ofType(PRODUCT_FETCHED),
    switchMap...
  )

  const deleteProduct$ = actions$.pipe(
    ofType(DELETE_PRODUCT),
    switchMap...
  )

  const editProduct$ = actions$.pipe(
    ofType(EDIT_PRODUCT),
    switchMap...
  )

  const addProduct$ = actions$.pipe(
    ofType(ADD_PRODUCT),
    switchMap...
  )

  const reorderProduct$ = actions$.pipe(
    ofType(REORDER_PRODUCT),
    switchMap...
  )

  and more...

  return getNavigation$.pipe(
    merge(productFetched$),
    merge(deleteProduct$),
    merge(editProduct$),
    merge(addProduct$),
    merge(reorderProduct$),
    merge(updateUniverseName$)
  )
}

export { merchEpic }
Randolf C.
@jun-sheaf
Check the documentation for ‘combineEpic’
Evert Bouw
@evertbouw
it's essentially what combineEpics does so this won't give performance problems, but it's not the easiest to maintain
nzsoori
@nzsoori
i have created 3 epics and combined one epic got Bearer token , can see characters data on load as "{,…}
docs: [{_id: "5cd99d4bde30eff6ebccfdf3", height: "", race: "Human", gender: "Male", birth: "SA 192",…},…]"
can't see characters data in store
nzsoori
@nzsoori
my_example.png
my_example_network.png
if you see in network it is connecting onload and getting characters, however it is the same url as books
see my booksepic it is almost same as characters
nzsoori
@nzsoori

see my booksepic it is almost same as characters and showing books

https://the-one-api.herokuapp.com/v1/character i am trying with Bearer Token
am stuck can you please help what is issue
@Sawtaytoes , @Kryotasin , @ktajpuri and @evertbouw

Kevin Ghadyani
@Sawtaytoes
@nzsoori Can you format your code with code ticks instead of as quoted text? Right now, it's very hard to follow. You can use 3 grave accents.
@nzsoori Also, I don't think you're using your epics correctly. I think I'm not understanding your code because I'm 99% sure RxJS don't throw errors in a try-catch.
@nzsoori Epics are always-listening. They're not "spin up and shut down" like you have. Your approach looks very strange to me, and that makes it difficult to understand what you're trying to accomplish.
nzsoori
@nzsoori
import { mergeMap, map } from "rxjs/operators";
import { ofType } from "redux-observable";
import { ajax } from "rxjs/ajax";
import { Observable } from "rxjs";

import {
  FETCH_BOOKS,
  fetchBooksFailure,
  fetchBooksSuccess,
} from "../actions/index";

let api = "https://the-one-api.herokuapp.com/v1/book";

function fetchBooksEpic(action$) {

  try {
    return action$.pipe(
      ofType(FETCH_BOOKS), 
      mergeMap(() => {

        return ajax.get(api).pipe(
          map((data) => Array.from(data.docs))         
        );       
      }),
      map((books) => fetchBooksSuccess(books)) 
    );
  } catch (error) {
    Observable.of(fetchBooksFailure(error.message));
  }
}

export default fetchBooksEpic;
import { API_TOKEN, api } from "../constants/demoConstants";

import { switchMap, mergeMap, map, flatMap } from "rxjs/operators";
import { ofType } from "redux-observable";
import { ajax } from "rxjs/ajax";

import { Observable } from "rxjs";
import {
  FETCH_CHARACTERS,
  fetchCharactersSuccess,
  fetchCharactersFailure,
} from "../actions/index";


let xhr = new XMLHttpRequest();
xhr.open("GET", api, true);
xhr.setRequestHeader("Authorization", "Bearer " + API_TOKEN);
xhr.send();

function fetchCharactersEpic(action$) {

  try {
    return action$.pipe(
      ofType(FETCH_CHARACTERS), 
      mergeMap(() => {      

        return ajax.getJSON(api).pipe(
          flatMap((data) => Array.from(data.docs.text())), 
          map((characters) =>
            characters.map((character) => ({
              id: character._id,
              name: character.name,
              wikiUrl: character.wikiUrl,
              spouse: character.spouse,
            }))
          )


        );
      }),
      map((characters) => fetchCharactersSuccess(characters)) 
    );
  } catch (error) {
    Observable.of(fetchCharactersFailure(error.message));
  }
}

export default fetchCharactersEpic;
nzsoori
@nzsoori
import { combineEpics } from "redux-observable";

import fetchWhiskiesEpic from "./fetchWhiskiesEpic";
import fetchBooksEpic from "./fetchBooksEpic";
import fetchCharactersEpic from "./fetchCharactersEpic";

export default combineEpics(
  fetchBooksEpic,
  fetchWhiskiesEpic,
  fetchCharactersEpic
);
import {
  FETCH_CHARACTERS,
  FETCH_CHARACTERS_FAILURE,
  FETCH_CHARACTERS_SUCCESS,
} from "../actions/index";

const initialState = {
  isLoaded: false,
  characters: [],
  error: null,
};

const charactersReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_CHARACTERS:
      return {
        ...state,
        // whenever we want to fetch the CHARACTERS, set isLoading to true to show a spinner
        isLoading: true,
        error: null,
      };

    case FETCH_CHARACTERS_SUCCESS:
      return {
        characters: [...action.payload],
        // whenever the fetching finishes, we stop showing the spinner and then show the data
        isLoading: false,
        error: null,
      };

    case FETCH_CHARACTERS_FAILURE:
      return {
        characters: [],
        isLoading: false,
        // same as FETCH_CHARACTERS_SUCCESS, but instead of data we will show an error message
        error: action.payload,
      };
    default:
      return state;
  }
};
export default charactersReducer;
import { combineReducers } from "redux";
import { connectRouter } from "connected-react-router";
import whiskysReducer from "./whiskysReducer";
import booksReducer from "./booksReducer";
import charactersReducer from "./charactersReducer";

const rootReducer = (history) =>
  combineReducers({
    router: connectRouter(history),
    whiskies: whiskysReducer,
    books: booksReducer,
    characters: charactersReducer,
  });

export default rootReducer;
import {
  FETCH_BOOKS,
  FETCH_BOOKS_FAILURE,
  FETCH_BOOKS_SUCCESS,
} from "../actions/index";

const initialState = {
  isLoaded: false,
  books: [],
  error: null,
};

const booksReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_BOOKS:
      return {
        ...state,
        // whenever we want to fetch the BOOKS, set isLoading to true to show a spinner
        isLoading: true,
        error: null,
      };

    case FETCH_BOOKS_SUCCESS:
      return {
        books: [...action.payload],
        // whenever the fetching finishes, we stop showing the spinner and then show the data
        isLoading: false,
        error: null,
      };

    case FETCH_BOOKS_FAILURE:
      return {
        books: [],
        isLoading: false,
        // same as FETCH_BOOKS_SUCCESS, but instead of data we will show an error message
        error: action.payload,
      };
    default:
      return state;
  }
};
export default booksReducer;
@Sawtaytoes have updated
Evert Bouw
@evertbouw
yeah use the catchError operator instead
Evert Bouw
@evertbouw
and set the auth header in ajax.get
function fetchCharactersEpic(action$) {
  return action$.pipe(
    ofType(FETCH_CHARACTERS),
    mergeMap(() =>
      ajax.getJSON(api, { Authorization: `Bearer ${API_TOKEN}` }).pipe(
        flatMap((data) => Array.from(data.docs.text())),
        map((characters) =>
          characters.map((character) => ({
            id: character._id,
            name: character.name,
            wikiUrl: character.wikiUrl,
            spouse: character.spouse,
          }))
        ),
        map((characters) => fetchCharactersSuccess(characters)),
        catchError((error) =>
          Observable.of(fetchCharactersFailure(error.message))
        )
      )
    )
  );
}
Kevin Ghadyani
@Sawtaytoes
@nzsoori ^^ Look at @evertbouw's comments
nzsoori
@nzsoori
Thanks appreciate guys @evertbouw and @Sawtaytoes , that worked
Bernat Jufré Martínez
@bjufre
Hey there! Having some problems with SSR, any inputs or suggestions? I've looked around but no luck. How do I dispatch the action and wait for the epic to resolve? Thanks!
Kevin Ghadyani
@Sawtaytoes

That's a good question. This is actually a React problem.

Server-side React doesn't run useEffect and will not work async.

The only way you can get this to work as you expect is to subscribe to store and wait for the values you want to exist. After that, render React server-side.

I know it's weird, but React doesn't have a way to run and run again when certain changes are made server-side. The way it works, it renders HTML and that's it. So you have to do all the work before React runs, then feed React all the data necessary to get the correct server-side output you're wanting.

@bjufre ^^ I'm assuming you're using React. You could be using regular HTML, but it's the exact same problem.
Jose Daniel Hernandez Rios
@d4nielhdz
Has anyone used rxfire with redux-observable? I'm trying to fetch data with firestore and I want an action to be dispatched on every emission of a new value, but I'm getting the error Actions must be plain objects. Use custom middleware for async actions.
My code looks like this

const fetchMenu = (action$, _state$) => {
  return action$.pipe(
    ofType(Types.FETCH_MENU_REQUESTED),
    flatMap((async ({ resID }) => {
      const firestore = firebase.firestore();
      const menuRef = firestore.collection('menus').where('resID', '==', resID);
      return collectionData(menuRef, 'id')
      .pipe(
        map(val => {
          console.log('vals');
          console.log(val);
          return Creators.fetchMenuSuccess(val);
        })
      )
    }
    )),
  );
};
Kevin Ghadyani
@Sawtaytoes
@d4nielhdz Does Creators.fetchMenuSuccess(val) return an regular old Redux action object with a type property?
@d4nielhdz Also, what's actually giving you that error message?
Jose Daniel Hernandez Rios
@d4nielhdz
Yes, Creators.fetchMenuSuccess is a valid action. I get the error when I use pipe.
>°))))彡
@fisherspy

Hi everyone, I have a question about combineLatest in Epic, after my app has been initiated, it will dispatch initAppCompleted only once, after that every time I jump to the focus page, it will dispatch fetchFocusPage action and request API.

Based on the info in https://stackoverflow.com/questions/42426908/how-to-delay-one-epic-until-another-has-emitted-a-value, using combineLatest must be alright.

But what happened is: after clicking the focus page, only the first time it outputs 'focus page epic entering'. Only If I manually dispatch initAppCompleted action after clicking the page, otherwise there is no request happening. I really don't know why.

here is my code(using Rxjs 6.5.4 & redux-observable 1.2.0):

export const focusPageFetchEpic: Epic<AnyAction, AnyAction, any> = (
  action$: ActionsObservable<Action>,
  state$: StateObservable<any>
) =>
  combineLatest([
    action$.pipe(filter(isActionOf(initAppCompleted)), tap(() => console.log('init action comming')), take(1)),
    action$.pipe(filter(isActionOf(fetchFocusPage)), tap(() => console.log('fetch action comming')))
  ]).pipe(
    tap(() => console.log('focus page epic entering'))
)
@Sawtaytoes @evertbouw
>°))))彡
@fisherspy
I have figured it out. the fetchFocusPage action has payload, if I dispatch the action without payload. Although the console will show 'fetch action coming', the process will not continue
Kevin Ghadyani
@Sawtaytoes
@d4nielhdz What's collectionData? An observable right?

@fisherspy It shouldn't matter about the payload. If both observables fire once, then it outputs values in your pipe. That's how combineLatest works. It waits for observables to output something once. After that happens, then you start receiving values in the combineLatest().pipe.

If you want something to emit when either observable emits, use merge instead of combineLatest.

>°))))彡
@fisherspy
But If I dispach{type: 'FOCUS_PAGE_FETCH' } instead of {type: 'Focus_PAGE_FETCH', payload: {}} with combineLatest. it only outputs value in my pipe the first time both observables fire once, after that if I fire one of them, it will not output values in my pipe, unless you fire both of them. with payload: {}, even just {}, combineLatest will work alright. I dont know whether it's a bug.
Pervez Alam
@pervezalam777
Can anyone share some complex Redux-Observable test-cases sample. I need to study how to write test cases which is close to real project code scenario.
Kevin Ghadyani
@Sawtaytoes
@pervezalam777
import { ActionsObservable } from 'redux-observable'

// ...

export const mockAjaxResponse = (
    mockedResponse,
) => ({
    ajax: () => (
        ActionsObservable
        .of({
            response: mockedResponse,
        })
    ),
})

// ...

fetchUserEpic(
    // action$
    ActionsObservable
    .of(
        fetchUser({ // this is a Redux action creator
            username: 'test@test.com',
            password: 'test',
        })
    ),

    // state$
    new BehaviorSubject({
        user: null,
    }),

    // Dependency injection
    mockAjaxResponse(),
)
@fisherspy I don't think it's a bug, but it might be something wonky in your setup. If it works for you, keep it that way. But what you're seeing sounds half-correct meaning there might be something else happening.