MichalZalecki / connect-rxjs-to-react

Connect rxjs to React component in Redux style... but without dispatch and constants.
187 stars 27 forks source link

Newbie issue #2 #8

Closed gnimmelf closed 6 years ago

gnimmelf commented 6 years ago

Hi again!

I didn't get the chance to continue with this last year I posted a newbie issue here, so while still at square one with both React and RxJs =(

How do you tie in the async part,

UserActions.fetch$.flatMap(userId => {
  return Rx.Observable.ajax(`/users/${userId}`)
});

With the actions already created?

import { createActions } from "../state/RxState";

export default createActions(["submit$", "reset$"]);

...and make it look DRY?

-What I don't understand is how the async part is tied into the reducer:

import Rx from "rxjs";
import { addSchemaError, log } from '../lib/utils';
import loginActions from "../actions/loginActions";

const authPath = window.AppSettings.authPath;

const initialState = {
  email: "aa@aa",
  errorSchema: {},
};

const LoginReducer$ = Rx.Observable.of(() => initialState)
  .merge(
    loginActions.submit$.map(payload => state => submitHandler(payload, state)),
    loginActions.reset$.map(_payload => _state => initialState),
  );

export default LoginReducer$;

function submitHandler(payload, state) {

  // THIS DOESN'T WORK; I need to `flatMap` it, but can't figure out where to do it
  return Rx.Observable.post(`${authPath}/request`, {email: payload.formData.email})

  //THIS IS HOW I WANT IT TO COME OUT, sort of
  const newState = {
    ...state,
    formData: payload.formData,
    errorSchema: addSchemaError(payload.errorSchema, 'email', errorFromAjaxPost),
  }

  return newState;
}

Thanks for your time!

gnimmelf commented 6 years ago

It's 2am, and I found a workaround; returning a promise from the reducer:

export function createState(reducer$, initialState$=Observable.of({})) {
  const publisher$ = Observable.empty()
    .merge(reducer$)
    .scan((promisedState, [scope, reducer]) => {

      return promisedState.then(state => {

        const reduced = reducer(state[scope]);

        if (reduced instanceof Promise) {
          return reduced.then(resolved => ({ ...state, [scope]: resolved }));
        }
        else {
          return Promise.resolve({ ...state, [scope]: reduced });
        }
      });

    }, initialState$.toPromise())
    .flatMap(promisedState => Observable.from(promisedState))
    .publishReplay(1)
    .refCount();

    return publisher$;
}

Still very interested in how you would have solved it =P Cheers! /Flemming

gnimmelf commented 6 years ago

Never mind, after 7 long nights I see how to use it as you wrote it. Love it! Cheers.