1.1.4 • Published 6 years ago
extendable-redux-store v1.1.4
extendable-redux-store
A small utility that helps to use async reducers
This library based on the article by Adam Rackis. For details, see here.
Table of contents
1. Installation
- For npm:
npm install extendable-redux-store
- For yarn:
yarn add extendable-redux-store
2. Set up
2.1. Create initial states and reducer stubs
You need to copy (do not import!) the initial state of the reducer you plan to load asynchroniously.
// Import all async reducer init states for defaults.
// We should COPY our init state for every reducer we plan to load asynchroniously.
// We can't just import it because in this casethe module will be included into the build
// and it wouldn't be loaded async.
const asyncReducerInitialState = {
payload: { messageAsync: null }
}
// Pre-register them to store to prevent warnings of undefined keys.
export const asyncReducersInitState = {
asyncReducer: asyncReducerInitialState
}
Reducer stub is needed to prevent warnings too. We use them while INITIALIZING THE STORE, do not think about them like about smth useful. They are needed to make redux store work as predictable storage.
import {asyncReducersStubs} from 'extendable-redux-store'
let asyncReducers = asyncReducersStubs(asyncReducersInitState) //{ asyncReducer: (state = '', action = {}) => {}, ... }
2.2. Create page-reducer map
/** import additional needed */
import { actions } from '../ducks/home'
export default {
'HOME': async store => {
// You can dispatch regular reducers here, too.
store.dispatch(actions.setMessage('Hi, I\'m from server!'))
// async stuff
const importResult = import(/* webpackChunkName: "duck-asyncReducer" */ /* webpackPrefetch: true */ './asyncHomeReducer')
// .then(mod => mod.default)
// .then(reducer => {
.then(duck => {
const {default: reducer, actions: asyncActions} = duck
store.addReducer('asyncReducer', reducer)
return asyncActions.setAsyncMessage(
`Once, yes, once, lived Crocodile.
Along the street he strolled in style.
Upon a fag he puffed (awhile)
And talked in Turkish (with a smile)
C. Crocodilovich Crocodile! // Korney Chukovsky`
)
// return {
// type: 'async/set',
// messageAsync: 'aaaaaaaaaaaaa'
// }
})
.then(action => store.dispatch(action))
await Promise.resolve(importResult)
},
'GALLERIES': async store => {
await Promise.resolve(store.removeReducer('asyncReducer'))
}
}
2.3. Configure store
import * as reducers from './reducers' // regular sync reducers
import {asyncReducersInitState} from './asyncReducers' // async init state
import pageToAsyncReducerMap from './asyncReducers/possibleReducersMap'
import {combineLazyReducers, asyncReducersStubs, createExtendableStore} from 'extendable-redux-store'
let asyncReducers = asyncReducersStubs(asyncReducersInitState) //{ asyncReducer: (state = '', action = {}) => {}, ... }
export default(history, preLoadedState = {
...asyncReducersInitState
}) => {
...
let store = createExtendableStore({
location: reduxRouterReducer,
...reducers
}, asyncReducers, preLoadedState, enhancers)
...
if (module.hot && process.env.NODE_ENV === 'development') {
module.hot.accept([
'./reducers/index',
'./asyncReducers/index', './asyncReducers/asyncHomeReducer', './asyncReducers/possibleReducersMap'
], () => {
pageToAsyncReducerMap[<HERE IS THE KEY OF YOUR CURRENT ROUTE>](store)
const reducers = require('./reducers/index')
const rootReducer = combineLazyReducers({
...reducers,
location: reduxRouterReducer,
...asyncReducers
}, store.getState())
store.replaceReducer(rootReducer)
})
}
...
return store
}
3. API
asyncReducersStubs(asyncReducersInitState)
- create async reducer stub from the copy of initial state of your async reducers;- params:
- asyncReducersInitState - combined initial state for all async reducer you plan to use;
- returns: reducers stub with keys from the initial state and values as stub reducer methods.
- params:
combineLazyReducers(reducers, initialState, shouldBeRemoved = false)
- params:
- reducers: all reducers, regular and stubs/async reducers;
- initialState: combined initial state, both regular and async;
- shouldBeRemoved: used only when remove async reducer;
- returns: combined reducer
createExtendableStore(syncReducers, asyncReducers, initState, enhancers)
- params:
- syncReducers: imported regular reducers;
- asyncReducers: async reducer stubs;
- initState: initial state combined, for both your regular and async reducers;
- enhancers - enhancers you use;
- returns: store
Using with Redux First Router
soon
Using with React-Router
soon
Server Side Rendering
soon
Thanks
- Reactjs team, especially Dan Abramov, for their amazing products;
- Adam Rackis for the idea and most part of the code;
- James Gillmore - for creating the Universal Component, Redux First Router (and many more);
- Zack Jackson - for his great help with React Universal Component, Babel plugin for it and many other things, he now supports and develops Redux First Router, React Universal Component after James Gillmore. See also the promising Rudy project.