How to handle multiple loads with redux-observable

544 views Asked by At

I'm having trouble loading multiple data with redux and redux-observable.

I need to load a Serie object, through ajax, that contains a list of questions and for each question I need to fetch it's images, audios and videos blobs, through ajax too.

As for now I am able to do this, but when I try to display my image in React, it doesn't work. I'm guessing that it sends the Serie object before having the images loaded, therefore it doesn't update the view once the blob retrieved. In fact if I add a delay in my Observable between the two maps, the images appear in the view.

I'm new to redux-observable (RxJS) and just trying to make it work even if it's not useful in my case.

Here is my action file.

import { Observable } from 'rxjs';

import { GET_SERIE, FETCH_SERIE } from './types';
import { ROOT_URL, SETTINGS } from './settings';

export function getSerie() {
  return { type: GET_SERIE }
}

function getBlob(assets) {
  return assets.map(asset => {
    fetch(asset.url_lg ? asset.url_lg : asset.url)
      .then(response => response.blob())
      .then(blob => asset['blob'] = URL.createObjectURL(blob))
    return asset;
  });
}

function getAssets(serie) {
  serie.questions.forEach(question => {
    question.pictures = getBlob(question.pictures);
    question.audios = getBlob(question.audios);
    question.videos = getBlob(question.videos);
  });

  return serie;
}

function setSerie(serie) {
  return {
    type: FETCH_SERIE,
    serie
  }
}

const fetchSerie = () =>
  fetch(`${ROOT_URL}/free_serie`, SETTINGS)
    .then((response) => response.json());

export const fetchSerieEpic = (action$) =>
  action$.ofType(GET_SERIE)
    .mergeMap((action) =>
      Observable.from(fetchSerie())
        .map(({ data }) => getAssets(data.serie))
        .map( serie => setSerie(serie))
    );

The reducer

import * as types from '../actions/types';

const initialState = {
  serie: null
};

export default function(state = initialState, action) {
  switch (action.type) {
    case types.FETCH_SERIE:
      return setSerie(state, action);
    default:
      return state;
  }
}

function setSerie(state, action) {
  const { serie } = action;

  return { ...state, serie };
}

And the view that dispatches the event

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../actions';

class App extends Component {
  componentWillMount() {
    this.props.fetchSerie();
  }

  render() {
    if(this.props.serie !== null) {
      return(
        <div>{this.props.children}</div>
      );
    }

    return <div>Loading ...</div>;
  }
}

function mapStateToProps(state) {
  const { serie } = state;

  return serie;
}

function mapDispatchToProps(dispatch) {
  return {
    fetchSerie: bindActionCreators(actions.getSerie, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

I've been looking multiple articles about redux and redux-observable, but found nothing that could help me.

0

There are 0 answers