All Projects → zaaack → nstate

zaaack / nstate

Licence: MIT license
A simple but powerful react state management library with low mind burden

Programming Languages

typescript
32286 projects
HTML
75241 projects

Projects that are alternatives of or similar to nstate

ddd-referenz
Deutsche Übersetzung der DDD Referenz von Eric Evans
Stars: ✭ 58 (+427.27%)
Mutual labels:  ddd, ddd-patterns, ddd-architecture
agile
🌌 Global State and Logic Library for JavaScript/Typescript applications
Stars: ✭ 90 (+718.18%)
Mutual labels:  state-management, simple, react-state-management
eShopOnWeb
Sample ASP.NET Core 6.0 reference application, powered by Microsoft, demonstrating a layered application architecture with monolithic deployment model. Download the eBook PDF from docs folder.
Stars: ✭ 8,250 (+74900%)
Mutual labels:  ddd, ddd-patterns, ddd-architecture
Example React Native Redux
react native redux counter example
Stars: ✭ 1,186 (+10681.82%)
Mutual labels:  state-management, simple
east-store
east-store is a state manager with easiest api that based hooks and immer.
Stars: ✭ 18 (+63.64%)
Mutual labels:  state-management, immer
react-evoke
Straightforward action-driven state management for straightforward apps built with Suspense
Stars: ✭ 15 (+36.36%)
Mutual labels:  state-management, immer
Vue Class Store
Universal Vue stores you write once and use anywhere
Stars: ✭ 243 (+2109.09%)
Mutual labels:  state-management, simple
awesome-software-architecture
A curated list of awesome articles, videos, and other resources to learn and practice software architecture, patterns, and principles.
Stars: ✭ 1,594 (+14390.91%)
Mutual labels:  ddd, ddd-architecture
dddplus-archetype-demo
♨️ Using dddplus-archetype build a WMS in 5 minutes. 5分钟搭建一个仓储中台WMS!
Stars: ✭ 56 (+409.09%)
Mutual labels:  ddd, ddd-architecture
Vogen
A semi-opinionated library which is a source generator and a code analyser. It Source generates Value Objects
Stars: ✭ 240 (+2081.82%)
Mutual labels:  ddd, ddd-patterns
nodejs-hexagonal-architecture-and-unit-test
This is a project to explain hexagonal architecture and unit tests in node.js
Stars: ✭ 99 (+800%)
Mutual labels:  ddd-patterns, ddd-architecture
rematch
The Redux Framework
Stars: ✭ 8,340 (+75718.18%)
Mutual labels:  state-management, immer
mutable
State containers with dirty checking and more
Stars: ✭ 32 (+190.91%)
Mutual labels:  state-management, class
Easy Peasy
Vegetarian friendly state for React
Stars: ✭ 4,525 (+41036.36%)
Mutual labels:  state-management, immer
Flutter Roadmap
This is a flutter roadmap and documentation repository. If anyone is interested you can join the party to help the community and make flutter great again.
Stars: ✭ 47 (+327.27%)
Mutual labels:  state-management, ddd-architecture
okito
Your best flutter coding friend. All in one; state management, navigation management(with dynamic routing), local storage, localization, dependency injection, cool extensions with best usages and with the support of best utilities!
Stars: ✭ 37 (+236.36%)
Mutual labels:  state-management, class
react-immer
No nonsense state management with Immer and React hooks
Stars: ✭ 13 (+18.18%)
Mutual labels:  state-management, immer
lamp-luwak
Service-oriented state management for React
Stars: ✭ 12 (+9.09%)
Mutual labels:  state-management, react-store
kanban core extension
DDD on Rails Example
Stars: ✭ 29 (+163.64%)
Mutual labels:  ddd, ddd-architecture
silex-ddd-skeleton
A simple skeleton of silex application using ddd arquitecture
Stars: ✭ 19 (+72.73%)
Mutual labels:  ddd, ddd-architecture

nstate

publish npm npm size

A simple but powerful react state management library with low mental load, inspired by rko.

nstate = nano state / next state

Contents

Features

  • Simple API with low mental load
  • Powerful features based on concise API.
  • Auto bind action methods
  • Combine stores and reuse actions/views
  • Watch store changes
  • Shipped with immer for nested state updating
  • Bind state field to form input with value/onChange/defaultValue
  • Flexible, you can customize all internal methods by override.

Install

yarn add nstate # or npm i nstate

API

export function setDebug(boolean):void // enable debug log

export default class NState<T> {
  protected state<T>
  protected events: Emitter<{
    change: { patch: any, old: T }
  }> // internal change events
  constructor(initialState: T, nameOrOptions?: string | { name: string, debug: boolean})
  protected onInit()
  protected setState(patch: Partial<T>)
  protected setState(patch: (s: T) => Partial<T>)
  protected setState(patch: (draft: T) => void) // using immer under the hood
  watch<U>(getter: (s: T) => U, handler: (s: U) => void) // Watch deep state change, if getter return a new array(length <= 20) or object, it will be shallow equals
  unwatch<U>(handler: (s: U) => void) // remove watch listener
  useWatch<U>(getter: (s: T) => U, handler: (s: U) => void, deps?: any[]) // watch hooks wrapper for auto remove handler after unmount and auto update when deps changes
  useState<U>(getter: (s: T) => U): U // use state hook, based on `watch`, so you can return a new array/object for destructuring.
  useBind<U>(getter: (s: T) => U): <K extends keyof U>(key: K, transformer?: (v: string) => U[K]) // bind state field to form input
  useSubStore<U>(getter: (s: T) => U, setter(s: T, u: U) => T) // create sub stores for get/set/watch, it will auto sync state to parent store
  dispose() // clear all event listeners, for sub stores/local stores
}

export function useLocalStore<T, U>(state: T, actions: (store: LocalStore<T>) => U): [T, LocalStore<T> & U]

Usage

1. Counter example

import NState, { setDebug } from 'nstate'
import React from 'react'

setDebug(true) // enable debug log

interface Store {
  count: number
}
export class CounterStore extends NState<Store> {

  inc() {
    // setState by new state
    this.setState({ count: this.state.count + 1 })
  }

  dec() {
    // setState by updater function like React
    this.setState(s => ({ count: s.count - 1 }))
  }

  set(n: number) {
    // setState by immer draft (using immer under the hood)
    this.setState(draft => {
      draft.count = n
    })
  }
}

export const counterStore = new CounterStore({ // optional initial state
  count: 0,
})

function Counter({ store = counterStore }: { store?: CounterStore }) {
  const count = store.useState(s => s.count)
  const inpRef = React.useRef<HTMLInputElement>(null)
  return (
    <div>
      <div>
        <h2>Counter</h2>
        <p>count: {count}</p>
        <button onClick={store.inc}>+</button>
        <button onClick={store.dec}>-</button>
        <button onClick={e=>store.set(0)}>reset</button>
      </div>
    </div>
  )
}

export default Counter

2. Bind state field to form input with onChange/value` with type safety

function Counter() {
  const count = counterStore.useState(s => s.count)
  const bind = counterStore.useBind(s => s) // you can also bind nested object with (s => s.xx.aa)
  return (
    <div>
      count: {count}
      <input type="text" {...bind('count', Number)} />
    </div>
  )
}

3. Combine multiple store to reuse actions/views

import NState, { setDebug } from 'nstate'
import React from 'react'
import Counter, {CounterStore} from './Counter';

setDebug(true) // enable debug log
interface Store {
  nest: {
    aa: string,
    bb: string,
  }
}
export class CombineStore extends NState<Store> {

  counter = new CounterStore({ count: 1 })

  onInit() {
    // link to counter store by simple watch API
    this.counter.watch(s=> s.count, count => {
      this.updateAA('count changed:'+count)
    })
  }

  updateAA(aa: string) {
    this.setState(draft => {
      draft.nest.aa = aa
    })
  }
  updateBB(bb: string) {
    this.setState(draft => {
      draft.nest.bb = bb
    })
  }
}

export const nestStore = new CombineStore({ // initial state
  nest: {aa: 'aa', bb: 'bb'},
})

function Combine() {
  // use state by destructuring, support array/object
  const [aa, bb] = nestStore.useState(s => [s.nest.aa, s.nest.bb])
  // or:
  // const {aa, bb} = nestStore.useState(s => ({aa: s.nest.aa, bb: s.nest.bb}))
  const inp1Ref = React.useRef<HTMLInputElement>(null)
  const inp2Ref = React.useRef<HTMLInputElement>(null)
  // watch hooks wrapper for auto remove handler after unmount
  nestStore.useWatch(s => [s.nest.aa, s.nest.bb], [aa, bb] => {
    // do something when state changes
  })
  return (
    <div>
      <div>
        <h2>Combine</h2>
        <Counter store={nestStore.counter} />
        <p>aa: {aa}</p>
        <p>bb: {bb}</p>
        <input ref={inp1Ref} type="text" defaultValue={aa}/>
        <button
          onClick={e => {
            nestStore.updateAA(inp1Ref.current?.value || '')
          }}
        >
          set aa
        </button>
        <input ref={inp2Ref} type="text" defaultValue={bb}/>
        <button
          onClick={e => {
            nestStore.updateBB(inp2Ref.current?.value || '')
          }}
        >
          set bb
        </button>
      </div>
    </div>
  )
}

export default Combine

4. useLocalStore

function CounterWithLocalStore() {
  const [count, store] = useLocalStore(0, store => ({
    inc: () => store.setState(s => s + 1),
    dec: () => store.setState(s => s - 1),
  }))
  return (
    <div>
      <div>
        <h2>Counter with useLocalStore</h2>
        <p>count: {count}</p>
        <button onClick={store.inc}>+</button>
        <button onClick={store.dec}>-</button>
        <button onClick={e=>store.setState(0)}>reset</button>
      </div>
    </div>
  )
}

5. useSubStore

interface Store {
  counter1: {
    count: number
  }
  counter2: {
    count: number
  }
}
export class Store extends NState<Store> {

}
export const store = new Store({ // initial state
  counter1: {count: 1},
  counter2: {count: 1},
})

function SubCounter({ store }) {
  return (
    <div>
      <div>
        <h2>Counter with useLocalStore</h2>
        <p>count: {count}</p>
        <button onClick={store.setState(s => s.count++)}>+</button>
        <button onClick={store.setState(s => s.count--)}>-</button>
        <button onClick={e=>store.setState(s => {
          s.count = 0
        })}>reset</button>
      </div>
    </div>
  )
}
function Counter() {
  const subStore = store.useSubStore(s => s.counter1, (s, u) => { s.counter1 = u })
  return <SubCounter store={subStore} />
}

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].