npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@plumbiu/react-store

v0.9.3

Published

Less than 1kb glob state management implement

Downloads

84

Readme

@plumbiu/react-store

Less than 1kb glob state management implement

import { createStore } from '@plumbiu/react-store'

const useCountStore = createStore({
  count: 15,
  inc() {
    this.$set({ count: this.count + 1 })
  },
})

export default function App() {
  const { count, inc } = useCountStore()
  // or use selector, it will avoid global subscriptions
  // const count = useCountStore('count')
  // const inc = useCountStore('inc')
  return (
    <>
      <div>count: {count}</div>
      <buttton onClick={inc}>inc</buttton>
    </>
  )
}

Immer

You can use createImmerStore api to reduce the nested structures:

const useImmerStore = createImmerStore({
  info: {
    address: {
      country: 'china',
    },
    age: 18,
  },
  changeAddress() {
    this.$set((draft) => {
      draft.info.address.province = 'hangzhou'
    })
  },
  changeAge() {
    this.$set((draft) => {
      draft.info.age++
    })
  },
})

Reading/writing state and reacting to changes outside of React Components

Sometimes we need access state outside React Components.

const store = createStore({ name: 'foo' })
// non-reactive fresh state
store.$getState() // { name: 'foo' }
// Updateding state outside component
store.$setState({ name: 'bar' })
store.$getState() // { name: 'bar' }
// Geting the initial state
store.$getInitialState() // { name: 'foo' }
// Updating state will trigger the listener
const unsub = store.$subscribe(console.log)
// Unscribe the listener
unsub()

Use $use api add plugin

persit

Cache data in localStorage:

import { createStore } from '@plumbiu/react-store'
import { persist } from '@plumbiu/react-store/plugins'

const usePersonStore = createStore({
  age: 21,
  name: 'foo',
  async changeAge(age: number) {
    this.$set({ age })
  },
  changeName() {
    this.$set({ name: this.name + '-' })
  },
})
// key for localStorage
usePersonStore.$use(persist({ key: 'person', age: 30000 }))

save

This is useful for some scenarios where you need to withdraw, such as withdrawing text in an input box.

import { createStore } from '@plumbiu/react-store'
import { save } from '@plumbiu/react-store/plugins'
import { useEffect } from 'react'
import hotkeys from 'hotkeys-js'

interface Data {
  value: string
  setValue: (value: string) => void
  save: () => void
  back: () => void
  // Properties starting with $ are considered ThisType
  $save: (point: string) => void
  $back: (point: string) => void
}

const SOME_POINT = 'some-point'
const useInputStore = createStore<Data>({
  value: '',
  setValue(value) {
    this.$set({ value })
  },
  save() {
    this.$save(SOME_POINT)
  },
  back() {
    this.$back(SOME_POINT)
  },
})

useInputStore.$use(save())

function App() {
  const data = useInputStore()
  const start = useRef(Date.now())
  useEffect(() => {
    hotkeys('alt+z', data.back)
  }, [])
  return (
    <input
      value={data.value}
      onBlur={() => {
        start.current = Date.now()
        data.save()
      }}
      onChange={(e) => {
        const now = Date.now()
        if (now - start.current > 200) {
          start.current = now
          data.save()
        }
        data.setValue(e.target.value)
      }}
    />
  )
}

Global Plugin

If you think it is troublesome to use the $use method to add plugins to createStore every time, you can create a custom createStore using a factory function.

For example, this save plugin:

import { createStoreFactory } from '@plumbiu/react-store'
import { save, type SaveThisType } from '@plumbiu/react-store/plugins'

// Generics added in ThisType
const createStore = createStoreFactory<SaveThisType>([save()])
const SOME_POINT = 'some-point'
const useInputStore = createStore({
  value: '',
  setValue(value: string) {
    this.$set({ value })
  },
  save() {
    this.$save(SOME_POINT)
  },
  back() {
    this.$back(SOME_POINT)
  },
})

Custom plugin

export interface Plugin<T> {
  // init state
  setup?: (state: T) => void
  // after re-render
  afterUpdate?: (prevState: T, nextState: T) => void
}

Simple persist

const store = createStore({
  age: '18',
  changeName() {
    this.$set({ age: this.age + 1 })
  },
})

const KEY = 'custom-plugin'
store.$use({
  setup(state) {
    const localStore = localStore.getItem(KEY)
    if (store === null) {
      return
    }
    const data = JSON.parse(localStore)
    for (const key in data) {
      state[key] = data[key]
    }
  },
  afterUpdate(_, nextState) {
    localStorage.setItem(KEY, JSON.stringify(nextState))
  },
})