1.1.4 • Published 5 years ago

extendable-redux-store v1.1.4

Weekly downloads
5
License
MIT
Repository
github
Last release
5 years ago

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.
  1. 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
  1. 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