medux
TypeScript icon, indicating that this package has built-in type declarations

1.2.0 • Public • Published

Medux: Modular immutable state management

Manage state and actions using immer

Getting Started

yarn add medux

Store

import { createStore } from 'medux'

const storeProps = {

  createState: () => ({
    count: 0
  }),
  
  actions: {
    increment(num = 1) {

      // `this` has getState, setState, actions

      // Produce new state by modifying draft
      this.setState(draft => {
        draft.count += num
      })

      // ..or merge into new state
      this.setState({
        count: this.state.count + 1
      })

      // Optionally call other actions
      this.actions.action()
    },

    // Action can be async
    async action(props) {}
  }  
}

const store = createStore(storeProps)

store.on('action', (key, props) =>{
  console.log('Action called', key, props)
  console.log('State changed', store.state)
})

store.actions.increment(5)

console.log(store.state) // { count: 5 }

Immutability

const oldState = store.state

store.actions.increment(5)

const newState = store.state // oldState !== newState

store.state.count++ // Error, must use setState or action

Core

If immutability is not needed, there's a much smaller core that can be imported.

import { createStore } from 'medux/core'

It has the same interface, but instead of using immer, it will mutate the store's state with Object.assign. This is simpler and faster, but does not have the benefits of immutability.

Context

For the createStore function, one can pass a property context with an object.

const storeContext = {}

createStore({
  context: storeContext
})

This is available to actions as this.context.

Events

The store instance is an event emitter with methods on, off, and emit.

They can be accessed from actions as this.on, this.off, this.emit.

const handler = data => {}

// Subscribe
store.on('eventName', handler)

// Unsubscribe
store.off('eventName', handler)

// Emit event

const data = {}

store.emit('eventName', data)

The on function returns an unsubscriber, which can be called with no arguments.

Child stores

const store = createStore({
  
  createState: () => ({
    ...parentState,
    child: childState
  }),

  actions: {
    ...parentActions,
    child: childActions
  }
})

store.actions.child.increment(5)

console.log(store.state.child) // { count: 5 }

Compose stores

The method composeStore creates a store from an array of store props.

This is a way to merge sets of states and actions.

import { composeStore } from 'medux' // or medux/core

const feature = {
  state: {},
  actions: {}
}

const anotherFeature = {
  state: {},
  actions: {}
}

const store = composeStore([
  feature,
  anotherFeature
], context)

Redux DevTools

import { connectReduxDevTools } from 'medux/redux-devtools'

const store = useStore(storeProps)

connectReduxDevTools(store)

React

The method useStore connects a component to a store, to render on state changes.

import { useStore } from 'medux/react'

const Component = () => {

  const store = useStore(storeProps)
  const { state, actions } = store

  return <button onClick={() => actions.increment()}>
    Increment: { state.count }
  </button>
}

It also accepts an array of store props, in which case their states and actions will be merged using composeStore.

The store can also be created outside the component, and passed to useStore.

import { createStore } from 'medux'
import { useStore } from 'medux/react'

const store = createStore(storeProps)

const Component = () => {

  useStore({ store })
  const { state, actions } = store

  return <button onClick={() => actions.increment()}>
    Increment: { state.count }
  </button>
}

React with Redux DevTools

import { useEffect } from 'react'
import { useStore } from 'medux/react'
import { connectReduxDevTools } from 'medux/redux-devtools'

const Component = () => {

  const store = useStore(storeProps)

  useEffect(() => {
    connectReduxDevTools(store)
  }, [])

  return ..
}

With options for Redux DevTools

connectReduxDevTools(store, options)

With store instance name

connectReduxDevTools('App', store, options)

Develop this library

Install dependencies

yarn

Develop: Watch files; Recompile, type check and test on changes

yarn dev

Build

yarn build

Publish to NPM

npm run release

Readme

Keywords

none

Package Sidebar

Install

npm i medux

Weekly Downloads

5

Version

1.2.0

License

MIT

Unpacked Size

26 kB

Total Files

23

Last publish

Collaborators

  • eliot