Redux-saga: Populating a component on load

Created on 5 Oct 2016  路  3Comments  路  Source: redux-saga/redux-saga

I'm trying to render the component only after the action is finished. But with sagas, my action is lost.

How do I return the saga a promise?

import { injectReducer } from '../../store/reducers'

export default (store) => ({
  path: 'example/:id',
  getComponent (nextState, cb) {
    require.ensure([], (require) => {

      const MainContainer = require('./containers/Main').default

      const actions = require('./modules').actions
      const reducer = require('./modules').reducers

      injectReducer(store, { key: 'example', reducer })

      // Uncaught TypeError: store.dispatch(...).then is not a function
      store
        .dispatch(actions.fetch(nextState.params.exampleId)) // set global spinner
        .then(() => cb(null, MainContainer)) // success, data loaded, render component
        .catch(cb) // return error to router (or render NotFoundComponent)
    })
  }
})
// Sagas

function* getExampleById(action) {
  const response = call(api.get) // ...
  yield put(exampleActions.success(response))
}

function* watchFetchExampleById() {
  yield takeEvery(EXAMPLE_FETCH.REQUEST, getExampleById)
}

export default function* root() {
  fork(watchFetchExampleById)
}

Most helpful comment

I have just two sagas so far which need to execute in sequence, but the component renders before either of them complete and fires an action before takeLatest has been hooked up.

This seems like a really common problem but the solution of yet another wrapper and manual prop checks to see if the saga is finished seems to take any of the benefits away of pure actions for me.

All 3 comments

I really aint sure what is yoru exact problem. Could you be more elaborate?

What is your expected behaviour?

Without completely understanding your issue (and guessing based on your title), I'd say the simplest way to defer rendering a component until a saga completes is to wrap the component in a {someProp && <MyChildComponent /> } from the parent component.

Example (assuming use of redux, but the idea is the same):

// ParentComponent.js
const ParentComponent = ({ myData }) => (
  { myData && <MyChildComponent /> /* this component will only render if myData is not undefined */ }
)
export default connect(state => ({ myData: state.myData }))(ParentComponent)

// sagas.js
function* getData() {
  var data = yield call(api.getData);
  yield put({type: 'GET_DATA_SUCCESS', data}));
}

export watchGetData() {
  yield takeEvery('GET_DATA', getData);
}

// reducers.js
function dataReducer(state, action) {
  //...
  case: 'GET_DATA_SUCCESS': 
    return {
      ...state,
      myData: action.data
    };
  //...
}

I have just two sagas so far which need to execute in sequence, but the component renders before either of them complete and fires an action before takeLatest has been hooked up.

This seems like a really common problem but the solution of yet another wrapper and manual prop checks to see if the saga is finished seems to take any of the benefits away of pure actions for me.

Was this page helpful?
0 / 5 - 0 ratings