# nycticorax

> State container for JavaScript application, and React

Latest version **4.2.1** (published 2026-08-07) · MIT license · 0 weekly downloads

## Install

```sh
npm install nycticorax
pnpm add nycticorax
yarn add nycticorax
bun add nycticorax
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 4.2.1 |
| Published | 2026-08-07 |
| First published | 2019-02-28 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 94.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 7 |
| Author | LoeiFy |
| Maintainers | loeify |
| Keywords | store, state, react |

## Links

- npm: https://www.npmjs.com/package/nycticorax
- Repository: https://github.com/fratercula/nycticorax
- Homepage: https://github.com/fratercula/nycticorax#readme
- Issues: https://github.com/fratercula/nycticorax/issues
- npm.io page: https://npm.io/package/nycticorax

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 4.2.1 (latest) — 2026-08-07
- 2.0.2 (next) — 2021-07-07
- 4.2.0 — 2025-12-29
- 4.1.4 — 2024-01-20
- 4.1.3 — 2024-01-14
- 4.1.2 — 2022-11-07
- 4.1.1 — 2022-11-06
- 4.1.0 — 2022-08-28
- 4.0.1 — 2022-08-13
- 4.0.0 — 2022-08-11
- 3.0.4 — 2022-08-06
- 3.0.3 — 2022-06-14
- 3.0.2 — 2022-04-27
- 3.0.1 — 2022-04-27
- 3.0.0 — 2022-04-27
- … 29 more at https://npm.io/package/nycticorax/versions

## README

# nycticorax

[![Build Status](https://github.com/fratercula/nycticorax/actions/workflows/ci.yml/badge.svg)](https://github.com/fratercula/nycticorax/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/fratercula/nycticorax/branch/master/graph/badge.svg)](https://codecov.io/gh/fratercula/nycticorax)

State container for JavaScript application, and React

https://fratercula.github.io/nycticorax/

## Install

```bash
$ npm i nycticorax
```

## Usage

For React, it is simple use, **not** `Provider`, `reducer`, `action`, **only** `connect`. `useStore` for Hooks


```tsx
import React, { Component } from 'react'
import Nycticorax from 'nycticorax'

type Store = { name: string, age: number }

const nycticorax = new Nycticorax<Store>()

const {
  createStore,
  dispatch,
  connect,
  useStore,
  emit,
} = nycticorax

createStore({ age: 0, name: 'abc' })

class A0 extends Component<Store> {
  onClick = () => {
    emit({ 'name': 'xyz' })
  }

  render() {
    const { name } = this.props
    return (
      <div>
        <p>{name}</p>
        <button onClick={this.onClick}>set</button>
      </div>
    )
  }
}

const A = connect('name')(A0)

// Hooks
function B() {
  const { name } = useStore('name')

  return (
    <div>
      <p>{name}</p>
      <button onClick={() => emit({ name: 'jkl' })}>name</button>
    </div>
  )
}

export default () => (
  <>
    <A />
    <B />
  </>
)
```

## API

width typescript

```ts
import Nycticorax, { Dispatch as DP } from 'nycticorax'

type Store = { name: string }

const nycticorax = new Nycticorax<Store>()

const {
  createStore,
  getStore,
  dispatch,
  subscribe,
  connect,
  useStore,
  emit,
} = nycticorax

type Dispatch = DP<Store>
```

width javascript

```js
import Nycticorax from 'nycticorax'

const nycticorax = new Nycticorax()

const {
  createStore,
  getStore,
  dispatch,
  subscribe,
  connect,
  useStore,
  emit,
} = nycticorax
```

without `React`

```ts
// not `connect` and `useStore`
import Nycticorax, { Dispatch as DP } from 'nycticorax/core'

type Store = { name: string }

const nycticorax = new Nycticorax<Store>()

const {
  createStore,
  getStore,
  dispatch,
  subscribe,
  emit,
} = nycticorax

type Dispatch = DP<Store>
```

### createStore

create store

```ts
type createStore = (state: T) => void

createStore({ name: 'nycticorax', [Symbol('key')]: 'symbol' })
```

### getStore

get store

```ts
type getStore<T> = (key? keyof T) => T | T[keyof T]

const store = getStore() // { name: 'nycticorax' }
const name = getStore('name')
```

### emit

update store

```ts
type emit = (next: Partial<T>, sync?: boolean) => void;

// update store key `name`, value is `xyz`
emit({ name: 'xyz' })

// multiple key
emit({ name: 'xyz', another: 1 })
```

by default, `emit` action will be `merged`

```js
emit({ a: 1, b: 2 })
emit({ b: 1 })

// will be merged as
emit({ a: 1, b: 1 })
```

set `emit` to `sync`

```js
createStore({ a: 1 })
emit({ a: 2 }, true)
console.log(getStore('a')) // { a: 2 }
```

### dispatch

```ts
const asyncDispatch: Dispatch = async ({ emit, getStore }, params) => {
  console.log(params)
  return new Promise((resolve) => {
    // get current store
    const { name } = getStore()

    // update name
    emit({ name: 'a' })

    setTimeout(() => {
      emit({ name: 'b' })

      // resolve
      resolve(name)
    }, 1000)
  })
}
dispatch(asyncDispatch, { a: 'b' }).then((name) => {
  console.log(name)
}
```

sync `emit`

```js
// async
createStore({ a: 1 })
emit({ a: 2 })
console.log(getStore('a')) // { a: 1 }
setTimeout(() => console.log(getStore('a'))) // { a: 2 }

function asyncDispatch({ emit, getStore }) {
  return new Promise((resolve) => {
    // update name
    emit({ name: 'a' }) // sync dispatch
    console.log(getStore('name')) // a

    setTimeout(() => {
      emit({ name: 'b' }) // sync dispatch
      console.log(getStore('name')) // b

      // resolve
      resolve(name)
    }, 1000)
  })
}
```

### subscribe

watch key change

```ts
type Listener<T> = (newValue: T, oldValue: T) => void;
type KeyWithListener<T> = Partial<Record<keyof T, Listener<T>>>;
type subscribe: (listener: KeyWithListener<T>) => () => void;

const unsubscribe = subscribe({
  time(newValue, oldValue) {
    console.log(newValue, oldValue)
  },
})
unsubscribe() // unsubscribe
```

### onChange

watch store change

```ts
type ChangeValue<T> = Record<keyof T, [newValue: T[keyof T], oldValue: T[keyof T]]>;
type OnChange<T> = (value: ChangeValue<T>) => void;

const nycticorax = new Nycticorax<Store>()

nycticorax.onChange = (v) => {
  console.log(v, 'onChange')
}
```

### connect

for `React` only

> class component cannot props `symbol` key, use `getStore` get symbol key`s value
> https://github.com/facebook/react/issues/7552

```tsx
type connect = (keys: (keyof T)[]) => (React.ComponentType) => React.ComponentType

const symbolKey = Symbol('key')

class A extends Component<Store> {
  render() {
    const { name, another } = this.props
    const store = getStore()
    return (
      <div>
        <h2>Component A</h2>
        <p>name: {name}</p>
        <p>{store[symbolKey]}</p>
      </div>
    )
  }
}

export default connect('name', symbolKey)(A)
```

### useStore

for `React` only

```tsx
type useStore = ((keyof T)[]) => T

function B() {
  const { name } = useStore('name')
  return (
    <>
      <p>{name}</p>
      <button onClick={() => emit({ name: 'jkl' })}>x</button>
    </>
  )
}
```

## License

MIT

---
_Source: https://npm.io/package/nycticorax · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
