All Projects → hmans → statery

hmans / statery

Licence: MIT license
Surprise-Free State Management! Designed for React with functional components, but can also be used with other frameworks (or no framework at all.)

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to statery

Reto
Flexible and efficient React Store with hooks.
Stars: ✭ 194 (+592.86%)
Mutual labels:  hooks, state-management
useSharedState
useSharedState is a simple hook that can be used to share state between multiple React components.
Stars: ✭ 0 (-100%)
Mutual labels:  hooks, state-management
Reusable
Reusable is a library for state management using React hooks
Stars: ✭ 207 (+639.29%)
Mutual labels:  hooks, state-management
Redhooks
Predictable state container for React apps written using Hooks
Stars: ✭ 149 (+432.14%)
Mutual labels:  hooks, state-management
use-app-state
🌏 useAppState() hook. that global version of setState() built on Context.
Stars: ✭ 65 (+132.14%)
Mutual labels:  hooks, state-management
React Model
The next generation state management library for React
Stars: ✭ 153 (+446.43%)
Mutual labels:  hooks, state-management
jedisdb
redis like key-value state management solution for React
Stars: ✭ 13 (-53.57%)
Mutual labels:  hooks, state-management
React Context Hook
A React.js global state manager with Hooks
Stars: ✭ 50 (+78.57%)
Mutual labels:  hooks, state-management
hooksy
Simple app state management based on react hooks
Stars: ✭ 58 (+107.14%)
Mutual labels:  hooks, state-management
resynced
An experimental hook that lets you have multiple components using multiple synced states using no context provider
Stars: ✭ 19 (-32.14%)
Mutual labels:  hooks, state-management
Pure Store
A tiny immutable store with type safety.
Stars: ✭ 133 (+375%)
Mutual labels:  hooks, state-management
react-zeno
The React companion to Zeno, a Redux implementation optimized for Typescript.
Stars: ✭ 14 (-50%)
Mutual labels:  hooks, state-management
React Atom
A simple way manage state in React, inspired by Clojure(Script) and reagent.cljs
Stars: ✭ 133 (+375%)
Mutual labels:  hooks, state-management
Use Url State
Lift a React component's state into the url
Stars: ✭ 154 (+450%)
Mutual labels:  hooks, state-management
Use Substate
🍙 Lightweight (<600B minified + gzipped) React Hook to subscribe to a subset of your single app state.
Stars: ✭ 97 (+246.43%)
Mutual labels:  hooks, state-management
dobux
🍃 Lightweight responsive state management solution.
Stars: ✭ 75 (+167.86%)
Mutual labels:  hooks, state-management
Pullstate
Simple state stores using immer and React hooks - re-use parts of your state by pulling it anywhere you like!
Stars: ✭ 683 (+2339.29%)
Mutual labels:  hooks, state-management
Use Global Context
A new way to use “useContext” better
Stars: ✭ 34 (+21.43%)
Mutual labels:  hooks, state-management
react-cool-form
😎 📋 React hooks for forms state and validation, less code more performant.
Stars: ✭ 246 (+778.57%)
Mutual labels:  hooks, state-management
use-query-string
🆙 A React hook that serializes state into the URL query string
Stars: ✭ 50 (+78.57%)
Mutual labels:  hooks, state-management

Version CI Downloads Bundle Size

                                          💥           ⭐️            💥      ✨
                             ✨                                ✨
  ███████╗████████╗ █████╗ ████████╗███████╗██████╗ ██╗   ██╗██╗   ✨
  ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██╔════╝██╔══██╗╚██╗ ██╔╝██║
  ███████╗   ██║   ███████║   ██║   █████╗  ██████╔╝ ╚████╔╝ ██║     ⭐️    ✨
  ╚════██║   ██║   ██╔══██║   ██║   ██╔══╝  ██╔══██╗  ╚██╔╝  ╚═╝
  ███████║   ██║   ██║  ██║   ██║   ███████╗██║  ██║   ██║   ██╗     ✨  💥
  ╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝   ╚══════╝╚═╝  ╚═╝   ╚═╝   ╚═╝        ✨
                                         ✨                 ✨   ⭐️
  SURPRISE-FREE STATE MANAGEMENT!                💥
                                                              ✨

Features 🎉

  • Simple, noise- and surprise-free API. Check out the demo!
  • Extremely compact, both in bundle size as well as API surface (2 exported functions!)
  • Fully tested, fully typed!
  • Designed for React (with functional components and hooks), but can also be used without it.

Non-Features 🧤

  • Doesn't use React Context (but you can easily use it to provide a context-specific store!)
  • Provides a simple set function for updating a store and not much else (have you checked out the demo yet?) If you want to use reducers or libraries like Immer, these can easily sit on top of your Statery store.
  • Currently no support for (or concept of) middlewares, but this may change in the future.
  • While the useStore hook makes use of proxies, the store contents themselves are never wrapped in proxy objects. (If you're looking for a fully proxy-based solution, I recommend Valtio.)
  • React Class Components are not supported (but PRs welcome!)

SUMMARY

import * as React from "react"
import { makeStore, useStore } from "statery"

/* Make a store */
const store = makeStore({ counter: 0 })

/* Write some code that updates it */
const increment = () =>
  store.set((state) => ({
    counter: state.counter + 1
  }))

const Counter = () => {
  /* Fetch data from the store (and automatically re-render
     when it changes!) */
  const { counter } = useStore(store)

  return (
    <div>
      <p>Counter: {counter}</p>
      <button onClick={increment}>Increment</button>
    </div>
  )
}

BASIC USAGE

Adding it to your Project

npm install statery

or

yarn add statery

Creating a Store

Statery stores wrap around plain old JavaScript objects that are free to contain any kind of data:

import { makeStore } from "statery"

const store = makeStore({
  player: {
    id: 1,
    name: "John Doe",
    email: "[email protected]"
  },
  gold: 100,
  wood: 0,
  houses: 0
})

Updating the Store

Update the store contents using its set function:

const collectWood = () =>
  store.set((state) => ({
    wood: state.wood + 1
  }))

const buildHouse = () =>
  store.set((state) => ({
    wood: state.wood - 10,
    houses: state.houses + 1
  }))

const Buttons = () => {
  return (
    <p>
      <button onClick={collectWood}>Collect Wood</button>
      <button onClick={buildHouse}>Build House</button>
    </p>
  )
}

Updates will be shallow-merged with the current state, meaning that top-level properties will be replaced, and properties you don't update will not be touched.

Reading from a Store (with React)

Within a React component, use the useStore hook to read data from the store:

import { useStore } from "statery"

const Wood = () => {
  const { wood } = useStore(store)

  return <p>Wood: {wood}</p>
}

When any of the data your components access changes in the store, they will automatically re-render.

Reading from a Store (without React)

A Statery store provides access to its current state through its state property:

const store = makeStore({ count: 0 })
console.log(store.state.count)

You can also imperatively subscribe to updates.

ADVANCED USAGE

Deriving Values from a Store

Just like mutations, functions that derive values from the store's state can be written as standalone functions:

const canBuyHouse = ({ wood, gold }) => wood >= 5 && gold >= 5

These will work from within plain imperative JavaScript code...

if (canBuyHouse(store.state)) {
  console.log("Let's buy a house!")
}

...mutation code...

const buyHouse = () =>
  store.set((state) =>
    canBuyHouse(state)
      ? {
          wood: state.wood - 5,
          gold: state.gold - 5,
          houses: state.houses + 1
        }
      : {}
  )

...as well as React components, which will automatically be rerendered if any of the underlying data changes:

const BuyHouseButton = () => {
  const proxy = useStore(store)

  return (
    <button onClick={buyHouse} disabled={!canBuyHouse(proxy)}>
      Buy House (5g, 5w)
    </button>
  )
}

Subscribing to updates (imperatively)

Use a store's subscribe function to register a callback that will be executed every time the store is changed. The callback will receive both an object containing of the changes, as well as the store's current state.

const store = makeStore({ count: 0 })

const listener = (changes, state) => {
  console.log("Applying changes:", changes)
}

store.subscribe(console.log)
store.set((state) => ({ count: state.count + 1 }))
store.unsubscribe(console.log)

Async updates

Your Statery store doesn't know or care about asynchronicity -- simply call set whenever your data is ready:

const fetchPosts = async () => {
  const posts = await loadPosts()
  store.set({ posts })
}

TypeScript support

Statery is written in TypeScript, and its stores are fully typed. useStore knows about the structure of your store, and if you're about to update a store with a property that it doesn't know about, TypeScript will warn you.

If the state structure makeStore infers from its initial state argument is not what you want, you can explicitly pass a store type to makeStore:

const store = makeStore<{ name?: string }>({})
store.set({ name: "Statery" }) // ✅  All good
store.set({ foo: 123 }) // 😭  TypeScript warning

NOTES

Stuff that probably needs work

  • No support for middleware yet. Haven't decided on an API that is adequately simple.
  • I have yet to try how Statery behaves in React's upcoming Concurrent Mode. It does work fine within React's StrictMode, though, so chances are it'll be okay.
  • Probably other bits and pieces I haven't even encountered yet.

Prior Art & Credits

Statery was born after spending a lot of time with the excellent state management libraries provided by the Poimandres collective, Zustand and Valtio. Statery started out as an almost-clone of Zustand, but with the aim of providing an even simpler API. The useStore hook API was inspired by Valtio's very nice useProxy.

Statery is written and maintained by Hendrik Mans. Get in touch on Twitter!

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].