ducksMiddleware
Extract all available middleware from a ducks object and creates a middleware with all available middleware.
It uses reducers defined as ducks, see ducks-modular-redux (aka isolated modules), and creates middleware that composes of existing middleware from ducks property middleware with no specific order that can be applyied with applyMiddleware.
Quick Use
Install with npm:
npm install ducks-middleware
// index.js const ducks = comments posts users const reducer = const middleware = // ...do your stuff... const store = // ...do your stuff...
// comments.js { } const middleware = { ; // Do here your middleware magic}; // ...
ducksMiddleware(ducks)
It creates a middleware with all the middleware from the given reducers.
It assumes that ducks may have a middleware property that can be composed as a single middleware.
const ducks = comments posts users const reducer = const middleware = const store =
// equivalent without ducksMiddlewareconst reducer = const store =
Because EcmaScript does not ensure any exact order to traverse Object properties, it is possible that middleware order can be altered from execution to execution.
// without ducksMiddleware any middleware order should be validconst reducer = const store =
If any duck has no middleware property, it is ignored.
// equivalent without ducksMiddleware in which users does not have middlewareconst reducer = const store =
Duck with Middleware Example
// posts.js // Actionsconst FETCH_POSTS = 'FETCH_POSTS'const FETCH_POSTS_FULFILLED = 'FETCH_POSTS_FULFILLED' // Action creatorsconst fetchPosts = type: FETCH_POSTS const fetchPostsFulfilled = type: FETCH_POSTS payload // Selectorsconst getPosts = stateposts // Reducer => { } // Middlewareconst middleware = async { ; if actiontype === FETCH_POSTS const response = await const payload = await response }
Why middleware instead of thunks
In the previous example, the middleware was the following:
const middleware = async { ; if actiontype === FETCH_POSTS const response = await const payload = await response }
the same logic can be implemented with a thunk
(in this case redux-async-thunk
) which requires to replace fetchPosts
with the following action creator:
const fetchPosts = { return async { const response = await const payload = await response }}
Both codes are almost the same, and satisfies the same behavior.
The difference is the extensibility and the responsibility inversion:
Once you have defined fetchPosts
in one duck module, you should not
change it. It will always fetch posts and nothing else.
¿What if you decide that you want also to fetch comments
at the same time than posts? You cannot unless you modify fetchPosts
.
With middlewares this limitation dissapears. Now in your comments duck you can add a middleware to add comments, just implement another middleware like the previous one but fetching comments:
; // ... const middleware = async { ; if actiontype === FETCH_POSTS else if actiontype === FETCH_COMMENTS const response = await const payload = await response }
Or, if you consider more convenient, keep comments duck simple and add fetch comments when fetching posts in an additional duck.
// ./comments.js // ... const middleware = async { ; if actiontype === FETCH_COMMENTS const response = await const payload = await response }
// ./posts-comments.js;; const middleware = { ; if actiontype === FETCH_POSTS }
Middlewares and system events
You can use middleware to generate actions from system events, for example:
// ./window-scroll.jsconst SCROLL_CHANGED = 'SCROLL_CHANGED';const scrollChanged = type: SCROLL_CHANGED ; const middleware = { if typeof window !== 'undefined' window return next}
See also
ducks-reducer to compose ducks reducers.
const ducks = comments posts users const reducer = const middleware = // ...do your stuff... const store = // ...do your stuff...