0.16.0 • Published 3 months ago

epic-state v0.16.0

Weekly downloads
-
License
CC-BY-NC-4.0
Repository
github
Last release
3 months ago

epic-state

Reactive state management for frontend libraries.

  • Reactive values, actions and derived states
  • Local and global plugins
  • Navigatable state-tree structure
  • Built-in TypeScript types
  • Automatic epic-jsx and Preact integration without component wrapper
  • Map, Set support

Usage

Any root state has to be created from an object while the returned Proxy can be used like regular JavaScript values.

import { state } from 'epic-state'

const root = state({
  count: 1,
  nested: { count: 2 },
  increment: () => {
    root.count *= 2
  },
  get double() {
    return root.count * 2
  },
})

To connect the state to automatically rerender epic-jsx components accessing the state add the following.

import { state, plugin } from 'epic-state'
import { connect } from 'epic-state/connect'
import { render } from 'epic-jsx'

plugin(connect) // Register global connect plugin for epic-jsx.

const root = state({
  count: 1,
})

render(
  <button
    onClick={() => {
      root.count += 1
    }}
  >
    Increment {root.count}
  </button>,
)

Observer

Using the observe method it's possible to receive notifications to state access or changes anywhere.

import { state, observe } from 'epic-state'
// TODO export observer type.
const myObserver = (action) => console.log(`Log: ${action}`)

const root = state({ count: 1 })
observe(myObserver)
// 'get' Action
const value = root.count // => Log: ['get', ['count'], 1]
// 'set' Action
root.count = 2 // => Log: ['get', ['count'], 2, 1]
// 'delete' Action
delete root.count // => Log: ['delete', ['count'], 2]

Data Structures

Using the observe method it's possible to receive notifications to state access or changes anywhere.

import { state, list } from 'epic-state'

const task = (name: string) => ({ name, done: false })
const root = state({ tasks: list(task, ['First Task', 'Second Task']) })

Plugins

Plugins - much like an observer - receive updates to the state but plugins can also be applied locally and defined for specific actions.

import { state, plugin } from 'epic-state'
import { connect } from 'epic-state/connect' // For epic-jsx
import { connect } from 'epic-state/preact' // For Preact
import { persistUrl } from 'epic-state/persist'

// Register plugin globally to any state updates.
plugin(connect)
// Add plugin to a local state.
const root = state({ count: 1, plugin: [connect] })
// Connect with configuration.
const root = state({ count: 1, page: 0, user: '123', plugin: [connect('page', 'user')] })

Build Your Own Plugin

Having access to state actions it's possible to encapsulate functionality as a plugin without the need for any changes to the regularly used code.

import { type Plugin, PluginActions } from 'epic-state'

function myConfigurableLogPlugin(...configuration: string[]): Plugin {
  let properties: string[] = []
  const isPropertyIgnored = () => properties.length !== 0 && !properties.includes(property)

  const actions = {
    get: ({ property, value }) =>
      !isPropertyIgnored(property) && console.log(`GET: ${property} as ${value}`),
    set: ({ property, value, previousValue }) => {
      if (value === previousValue || isPropertyIgnored(property)) return
      console.log(`SET: ${property} as ${value} from ${previousValue}`)
    },
    delete: ({ property }) =>
      !isPropertyIgnored(property) && console.log(`DELETE: ${property}`),
  } as PluginActions

  // Called last by the library when a plugin is added to the state.
  if (configuration[0] === 'initialize') {
    return actions
  }

  properties = properties.concat(configuration ?? [])

  return (...innerConfiguration: any) => {
    // Plugin should only be configured once.
    if (innerConfiguration[0] !== 'initialize') {
      console.error('Plugin has already been configured')
    }
    return actions
  }
}
0.16.0

3 months ago

0.15.4

4 months ago

0.15.5

4 months ago

0.15.6

4 months ago

0.15.2

4 months ago

0.15.3

4 months ago

0.15.0

4 months ago

0.15.1

4 months ago

0.14.0

5 months ago

0.13.0

6 months ago

0.12.0

10 months ago

0.11.0

10 months ago

0.10.1

10 months ago

0.10.0

10 months ago

0.9.0

10 months ago

0.8.2

10 months ago

0.8.1

10 months ago

0.8.0

10 months ago

0.7.2

11 months ago

0.7.1

11 months ago

0.7.0

11 months ago

0.6.0

12 months ago

0.5.3

1 year ago

0.5.2

1 year ago

0.5.1

1 year ago

0.5.0

1 year ago

0.4.0

1 year ago

0.3.0

1 year ago

0.1.0

2 years ago

0.2.0

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago