Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chainable asynchronous middlewares #1584

Closed
recidive opened this issue Apr 6, 2016 · 2 comments
Closed

Chainable asynchronous middlewares #1584

recidive opened this issue Apr 6, 2016 · 2 comments

Comments

@recidive
Copy link

recidive commented Apr 6, 2016

Hello, we are trying to create modules made of a redux reducer and/or a middleware. The modules are to be reused and distributed, mostly like Ducks does, but also supporting middlewares.

We are using redux actions and trying to do something useful asynchronously, like reading a file or something from the database, and also allow a chain of dependency where modules' middlewares/reducers can rely on the state/payload of the module it depends on, and use it to build and return a new state.

Something like:

module 1
-> dispatch action to read something async
-> query database middleware await data from database
-> run all other modules (async/sync) middlewares
-> reducer consumes data and build a new state
-> then it's passed to module 2 reducer and so on...

For doing so we are trying to run through a chain of (synchronous and asynchronous) side-effects in middlewares.

We don't want to do anything other than returning the FSA object when defining actions, so we don't restrict the data gathering logic and any other business logic only to the module that creates the action and centralize them in middlewares.

import {createStore, applyMiddleware} from 'redux'
import {createAction, handleActions} from 'redux-actions'
import promiseMiddleware from 'redux-promise'

const BOOT = 'BOOT'
const AFTER_BOOT = 'AFTER_BOOT'
const AFTER_AFTER_BOOT = 'AFTER_AFTER_BOOT'

const someApi = {
 get(id) {
   return Promise.resolve({
     name: 'yeah'
   })
 }
}

const bootAction = createAction(BOOT)

const afterBootAction = createAction(AFTER_BOOT, async (id) => {
 const result = await someApi.get(id)
 return result
})

const afterAfterBootAction = createAction(AFTER_AFTER_BOOT, async (id) => {
 const result = await someApi.get(id)
 return result
})

const initialState = {foo: 'bar'}

const reducer = (state = initialState, action) => {
 switch (action.type) {
   case AFTER_BOOT:
     return {
       ...state,
       foo: 'baz'
     }

   case AFTER_AFTER_BOOT:
     return {
       ...state,
       foo: 'rock'
     }
   default:
     return state
     break
 }
}

const middlewares = [
 function middle({getState, dispatch}) {
   // Note the async keyword.
   return next => async (action) => {

     if (action.type == BOOT) {
       const sideffectA = await dispatch(afterBootAction(2))
     }

     if (action.type == AFTER_BOOT) {
       const sideffectB = await dispatch(afterAterBootAction(3))
     }

     return next(action)
   }
 },
 promiseMiddleware
]

const store = createStore(reducer, initialState, applyMiddleware(...middlewares))

// First action, and should fire other side-effects.
store.dispatch(bootAction())

console.log(store.getState(), "It should print {foo: 'rock'}")

We are doing this as part of our Choko Redux project.

@sebas5384
Copy link

Seems to be a long discussion about side-effects here #1528

@recidive
Copy link
Author

This is resolved in redux-boot. This centralizes all side-effects in middlewares, despite they are sync or async.

This helps reduce boilerplate and having a uniform way for grouping reducers and middlewares.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants