Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Iron Redux | 298 | a year ago | 2 | mit | TypeScript | |||||
Painless typesafe Redux code generator | ||||||||||
React Test Demo | 156 | 4 years ago | JavaScript | |||||||
Web 前端单元测试到底要怎么写?看这一篇就够了 | ||||||||||
Redux Api Call | 68 | 5 | 2 | a year ago | 66 | August 16, 2022 | mit | JavaScript | ||
One declarative API to create reducers, action creators and selectors for any API calls | ||||||||||
Redux Fetch Middleware | 36 | 1 | 1 | 10 months ago | 39 | October 16, 2018 | 1 | mit | JavaScript | |
The simplest middleware using fetch api for redux to send request | ||||||||||
Fusion Baseui | 30 | 4 years ago | 2 | JavaScript | ||||||
Simple app using Fusion.js and Base UI | ||||||||||
React Redux Api Tools | 30 | 1 | 1 | 3 years ago | 13 | June 23, 2020 | mit | JavaScript | ||
A set of tools to facilitate react-redux development and decouple logic from compontents | ||||||||||
Redux Fetcher | 20 | 4 | 1 | 7 years ago | 5 | August 12, 2016 | 2 | mit | JavaScript | |
Simple isomorphic fetch for Redux | ||||||||||
Next Mvc | 18 | 5 years ago | 12 | August 01, 2018 | mit | JavaScript | ||||
An isomorphic mvc framework based on next.js, react, redux and immer | ||||||||||
Hermes Js | 14 | 5 years ago | 18 | May 24, 2018 | mit | JavaScript | ||||
Universal action dispatcher for JavaScript apps | ||||||||||
Generator React Redux App | 13 | 2 | 8 years ago | 6 | January 23, 2016 | 2 | JavaScript | |||
Yeoman generator for React with Redux. Webpack, ES6, Mocha, Express. |
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.
Install with npm:
npm install ducks-middleware
// index.js
import ducksReducer from 'ducks-reducer'
import ducksMiddleware from 'ducks-middleware'
import * as comments from './comments'
import * as posts from './posts'
import * as users from './users'
const ducks = { comments, posts, users }
const reducer = ducksReducer(ducks)
const middleware = ducksMiddleware(ducks)
// ...do your stuff...
const store = createStore(
reducer,
preloadedState,
applyMiddleware(middleware)
)
// ...do your stuff...
// comments.js
export default function commentsReducer(state, action) {
switch (action.type) {
// Do here your reducer magic
default: return state
}
}
export const middleware = store => next => action => {
next(action);
// Do here your middleware magic
};
// ...
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 = ducksReducer(ducks)
const middleware = ducksMiddleware(ducks)
const store = createStore(
reducer,
preloadedState,
applyMiddleware(middleware)
)
// equivalent without ducksMiddleware
const reducer = ducksReducer({ comments, posts, users })
const store = createStore(
reducer,
preloadedState,
applyMiddleware(comments.middleware, posts.middleware, users.middleware)
)
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 valid
const reducer = ducksReducer({ comments, posts, users })
const store = createStore(
reducer,
preloadedState,
applyMiddleware(comments.middleware, users.middleware, posts.middleware)
)
If any duck has no middleware property, it is ignored.
// equivalent without ducksMiddleware in which users does not have middleware
const reducer = ducksReducer({ comments, posts, users })
const store = createStore(
reducer,
preloadedState,
applyMiddleware(comments.middleware, posts.middleware)
)
// posts.js
// Actions
export const FETCH_POSTS = 'FETCH_POSTS'
export const FETCH_POSTS_FULFILLED = 'FETCH_POSTS_FULFILLED'
// Action creators
export const fetchPosts = () => ({ type: FETCH_POSTS })
export const fetchPostsFulfilled = (payload) => ({
type: FETCH_POSTS,
payload,
})
// Selectors
export const getPosts = (state) => state.posts
// Reducer
export default function postsReducer(state = [], action) => {
switch (action.type) {
case FETCH_POSTS_FULFILLED:
return action.payload
default: return state
}
}
// Middleware
export const middleware = ({ dispatch }) => next => async (action) => {
next(action);
if (action.type === FETCH_POSTS) {
const response = await fetch('/api/posts')
const payload = await response.json()
dispatch(fetchPostsFulfilled(payload))
}
}
In the previous example, the middleware was the following:
export const middleware = ({ dispatch }) => next => async (action) => {
next(action);
if (action.type === FETCH_POSTS) {
const response = await fetch('/api/posts')
const payload = await response.json()
dispatch(fetchPostsFulfilled(payload))
}
}
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:
export const fetchPosts = () => {
return async ({ dispatch }) => {
dispatch({ type: FETCH_POSTS })
const response = await fetch('/api/posts')
const payload = await response.json()
dispatch(fetchPostsFulfilled(payload))
}
}
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:
import FETCH_POSTS from '../posts';
// ...
export const middleware = ({ dispatch }) => next => async (action) => {
next(action);
if (action.type === FETCH_POSTS) {
dispatch(fetchComments())
} else if (action.type === FETCH_COMMENTS) {
const response = await fetch('/api/comments')
const payload = await response.json()
dispatch(fetchCommentsFulfilled(payload))
}
}
Or, if you consider more convenient, keep comments duck simple and add fetch comments when fetching posts in an additional duck.
// ./comments.js
// ...
export const middleware = ({ dispatch }) => next => async (action) => {
next(action);
if (action.type === FETCH_COMMENTS) {
const response = await fetch('/api/comments')
const payload = await response.json()
dispatch(fetchCommentsFulfilled(payload))
}
}
// ./posts-comments.js
import FETCH_POSTS from '../posts';
import fetchComments from '../comments';
export const middleware = ({ dispatch }) => next => action => {
next(action);
if (action.type === FETCH_POSTS) {
dispatch(fetchComments())
}
}
You can use middleware to generate actions from system events, for example:
// ./window-scroll.js
export const SCROLL_CHANGED = 'SCROLL_CHANGED';
export const scrollChanged = () => ({ type: SCROLL_CHANGED });
export const middleware = ({ dispatch }) => {
if (typeof window !== 'undefined') {
window.addEventListener('scroll', () => {
dispatch(scrollChanged())
})
}
return next => next
}
ducks-reducer to compose ducks reducers.
import ducksReducer from 'ducks-reducer'
import ducksMiddleware from 'ducks-middleware'
import * as comments from './comments'
import * as posts from './posts'
import * as users from './users'
const ducks = { comments, posts, users }
const reducer = ducksReducer(ducks)
const middleware = ducksMiddleware(ducks)
// ...do your stuff...
const store = createStore(
reducer,
preloadedState,
applyMiddleware(middleware)
)
// ...do your stuff...