Coder Social home page Coder Social logo

bey's Introduction

bey

Simple immutable state for React using Immer

  • ~700B minified and gzipped (not including React & Immer)
  • Try it out alongside other state solutions
  • Heavily inspired by react-copy-write

Install

yarn add bey

Example

import React from 'react';
import { render } from 'react-dom';
import { state, update, Subscribe } from 'bey';

let counter = state({
  count: 0,
});

function increment() {
  update(counter, state => { state.count++ });
}

function decrement() {
  update(counter, state => { state.count-- });
}

function Counter() {
  return (
    <Subscribe to={counter} on={state => state.count}>
      {count => (
        <div>
          <button onClick={decrement}>-</button>
          <span>{count}</span>
          <button onClick={increment}>+</button>
        </div>
      )}
    </Subscribe>
  );
}

render(<Counter/>, window.root);

Run this example locally by cloning the repo and running yarn example in the root directory.

Guide

state()

First you'll need to create some state containers for your app.

let counter = state({
  count: 0
});

Call state() with your initial state and you're good to go.

This returns a small object which we can subscribe to, update, and get the current state from.

update()

You'll want to create some "actions" that will update your state when called. These should just be plain functions that call update() inside.

let counter = state({
  count: 0
});

function increment() {
  update(counter, state => { state.count++; });
}

function decrement() {
  update(counter, state => { state.count--; });
}

When you call update() you'll pass your state container and an "updater" function. Inside the "updater" function is just passed through to Immer (You'll want to read about that works).

You'll notice that inside the updater function you can just mutate whatever you want. Don't mutate outside of the updater function though.

<Subscribe/>

Finally, you'll need a way to subscribe to state updates and re-render your tree.

function Counter() {
  return (
    <Subscribe to={counter}>
      {state => <span>{state.count}</span>}
    </Subscribe>
  );
}

If you only need part of your state, you get pass an optional on prop which selects just the state you care about and passes it through to the children function.

function Counter() {
  return (
    <Subscribe to={counter} on={state => state.count}>
      {count => <span>{count}</span>}
    </Subscribe>
  );
}

This also acts as an optimization when you have a large state object but only need to re-render when a nested value in that state object is updated.

If you need multiple values, you can return an object:

<Subscribe to={user} on={state => ({ name: state.name, username: state.username })}>
  {({ name, username }) => <span>{name} (@{username})</span>}
</Subscribe>

The same optimizations will apply using the same shallow equality check that React uses.

Calling actions

Actions can be called at any time from any part of your app.

let counter = state({ count: 0 });

function increment() {
  update(counter, state => { state.count++; });
}

function Increment() {
  return <button onClick={increment}>+</button>;
}

Multiple instances of containers

If you need to create multiple instances of containers, wrap your state() call in a factory:

let createCounter = () => {
  return state({ count: 0 });
};

Remember that your methods for updating state are just functions, don't be afraid to write them however you need. So here we can pass the state object we are updating as a parameter.

function increment(counter) {
  update(counter, state => { state.count++; });
}

function decrement(counter) {
  update(counter, state => { state.count--; });
}

Then inside your components where you call those methods, pass the state objects in:

function Counter(props) {
  return (
    <Subscribe to={props.counter} on={state => state.count}>
      {count => (
        <div>
          <button onClick={() => decrement(props.counter)}>-</button>
          <span>{count}</span>
          <button onClick={() => increment(props.counter)}>+</button>
        </div>
      )}
    </Subscribe>
  );
}

function Counters(props) {
  return (
    <div>
      <Counter counter={createCounter()}/>
      <Counter counter={createCounter()}/>
    </div>
  );
}

bey's People

Contributors

alex-kinokon avatar charliewilco avatar jamiebuilds avatar lostpebble avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.