Skip to content
This repository has been archived by the owner on Jan 27, 2021. It is now read-only.

Latest commit

 

History

History

redux-dynostore-core

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

@redux-dynostore/core

Deprecated

This library is no longer being actively maintained.

IOOF has been slowly moving away from the ubiquitous use of Redux as a core piece of our micro-frontend architecture and have been actively replacing the usage of this library with more standard React and JavaScript patterns. Due to some technical constraints, we've also been unable to upgrade to the latest version of the library ourselves for quite some time now, further fuelling our desire to move away from this solution.

At this time, we will be ceasing all maintenance tasks and we recommend that you consider using an alternative library:

If you want to continue using this library, we encourage you to fork this repo and take over maintenance yourself.


build status npm version npm downloads License: BSD-3-Clause

Core library to add dynamic enhancers to redux stores.

Usage

import dynostore from '@redux-dynostore/core'

const store = createStore(reducer, dynostore(dynamicEnhancer(), dynamicEnhancer2('with parameters')))

Options

An optional options object can be passed as the final parameter to the dynostore function:

import dynostore, { dynamicReducers } from '@redux-dynostore/core'

const store = createStore(
  reducer,
  dynostore(dynamicReducers(), {
    /* options */
  })
)

When provided, the options are available to enhancers to use as default options or for handling common options between multiple enhancers. How options are used will depend of the specific enhancer implementations, so refer to their individual documentation for details.

Enhancers

Dynamic enhancers are used to make dynamic features available to the store. The following dynamic enhancers are provided:

  1. Reducers - dynamically attach reducers
  2. Sagas - dynamically run sagas

dynamicReducers

import dynostore, { dynamicReducers } from '@redux-dynostore/core'

const store = createStore(reducer, dynostore(dynamicReducers()))

Manually attaching reducers

If you aren't using react, or want to attach a reducer outside of the component lifecycle, the store now has an attachReducers function that can be used to add additional reducers after the store has been created:

store.attachReducers({ dynamicReducer })

Multiple reducers can be attached as well:

store.attachReducers({ dynamicReducer1, dynamicReducer2 })

Reducers can also be added to nested locations in the store. The following formats are supported:

store.attachReducers({ 'some.path.to': dynamicReducer })
store.attachReducers({ 'some/path/to': dynamicReducer })
store.attachReducers({
  some: {
    path: {
      to: {
        dynamicReducer
      }
    }
  }
})

Detaching reducers

If you need to remove a reducer from the store, the detachReducers function that can be used:

store.detachReducers(['dynamicReducer'])

Multiple reducers can be detached at the same time as well:

store.detachReducers(['dynamicReducer1', 'dynamicReducer2'])

Nested reducers can also be removed by using the full path to the reducer. The following formats are supported:

store.detachReducers(['some.path.to.dynamicReducer'])
store.detachReducers(['some/path/to/dynamicReducer'])

Note: only reducers that were added using an the attachReducer function can be detached. Static reducers cannot be detached from the store.

Options

dynamicReducers accepts options to modify it's behaviour. Default options can be overridden when creating the dynamicReducers enhancer:

import dynostore, { dynamicReducers } from '@redux-dynostore/core'

const store = createStore(
  reducer,
  dynostore(
    dynamicReducers({
      /* options */
    })
  )
)

Options can also be overridden for specific reducers when attaching them to the store:

store.attachReducers(
  { 'some.path.to': dynamicReducer },
  {
    /* options */
  }
)

Note: All the reducers being attached in a single attachReducers call will use the same provided options.

stateHandler
const store = createStore(reducer, dynostore(dynamicReducers(), { stateHandler: customStateHandler }))
const store = createStore(reducer, dynostore(dynamicReducers({ stateHandler: customStateHandler })))
store.attachReducers({ 'some.path.to': dynamicReducer }, { stateHandler: customStateHandler })

The stateHandler option is used to modify the behaviour of dynamicReducers when interacting with the state tree. They can be used to optimize for different goals, such as accuracy or performance, or to support alternative state structures, such as ImmutableJS.

State handlers are provided as an object with the following functions:

Name Description Example
createEmpty() Create an empty container for the state () => ({})
getKeys(state) Get the avaialble keys of the state (state) => Object.keys(state)
getValue(state, key) Selects a value from the state (state, key) => state[key]
setValue(state, key, value) Sets a value in the state and return the new state (state, key, value) => ({ ...state, [key]: value }
canMerge(state) Check if the state is of a mergable type (state) => state && typeof state === 'object' && !Array.isArray(state)
merge(oldState, newState) Merges the new state and old state into a new state (oldState, newState) => ({ ...oldState, newState })

redux-dynostore provides the following built-in state handlers:

  • shallowStateHandler (default): handles plain Javascript types and shallow merges the state when combining the state from different reducers
  • deepStateHandler : handles plain Javascript types and deep merges the state when combining the state from different reducers
  • defaultStateHandler: an alias for shallowStateHandler

The deepStateHandler will generally create more accurate state trees and allows for dynamic reducers to attach to node of the state tree owned by a static reducer, but at the cost of performance. Using the shallowStateHandler will generally be more performant, but comes with the previously mentioned constraints.

Note: There is a known issue with the deepStateHandler and that prevents reducers from ever removing nodes of the state tree. For this reason, it is currently adviser not to use this state handler unless you are confident that this will not affect you.

Custom Enhancers

Dynamic enhancers can be created for many use cases by implementing the following interface:

const enhancer = createHandlers => (store, reducer, preloadedState) => ({ ...handlers })

handlers is an object with all the functions you want your enhancer to add to the store. You should only ever append your handlers to the object and not remove any added by other dynamic handlers.

Utilities

attachReducer

An enhancer compatible with react-redux-dynostore to attach the reducer when activated:

import dynamic from '@redux-dynostore/react-redux'
import { attachReducer } from '@redux-dynostore/core'

export default dynamic('identifier', attachReducer(myReducer))(MyComponent)

The same options that can be provided to store.attachReducers (above) can also be provided to the attachReducer enhancer as the second parameter:

export default dynamic('identifier', attachReducer(myReducer, { stateHandler: customStateHandler }))(MyComponent)

dispatchAction

An enhancer compatible with react-redux-dynostore to dispatch an action when activated:

import dynamic from '@redux-dynostore/react-redux'
import { dispatchAction } from '@redux-dynostore/core'

export default dynamic('identifier', dispatchAction({ type: 'MY_ACTION' }))(MyComponent)