Giter VIP home page Giter VIP logo

constate's Introduction

constate logo



Generated with nod NPM version Build Status Coverage Status



context + state = constate

~2kB React state management library that lets you work with local state and scale up to global state with ease when needed.

Demo: https://codesandbox.io/s/7p2qv6mmq

Install

npm i -S constate

Usage

Table of Contents

Local state

You can start by creating your State component:

import React from "react";
import { State } from "constate";

export const initialState = {
  count: 0
};

export const actions = {
  increment: amount => state => ({ count: state.count + amount })
};

export const selectors = {
  getParity: () => state => (state.count % 2 === 0 ? "even" : "odd")
};

const CounterState = props => (
  <State
    initialState={initialState}
    actions={actions}
    selectors={selectors}
    {...props}
  />
);

export default CounterState;

Note: the reason we're exporting initialState, actions and selectors is to make testing easier.

Then, just use it elsewhere:

const CounterButton = () => (
  <CounterState>
    {({ count, increment, getParity }) => (
      <button onClick={() => increment(1)}>{count} {getParity()}</button>
    )}
  </CounterState>
);

Global state

Whenever you need to share state between components and/or feel the need to have a global state, you can pass a context property to State and wrap your app with Provider:

const CounterButton = () => (
  <CounterState context="counter1">
    {({ increment }) => <button onClick={() => increment(1)}>Increment</button>}
  </CounterState>
);

const CounterValue = () => (
  <CounterState context="counter1">
    {({ count }) => <div>{count}</div>} 
  </CounterState>
);

const App = () => (
  <Provider>
    <CounterButton />
    <CounterValue />
  </Provider>
);

Composing state

This is still React, so you can pass new properties to CounterState, making it really composable.

First, let's change our CounterState so as to receive new properties:

const CounterState = props => (
  <State
    {...props}
    initialState={{ ...initialState, ...props.initialState }}
    actions={{ ...actions, ...props.actions }}
    selectors={{ ...selectors, ...props.selectors }}
  />
);

Now we can pass new initialState, actions and selectors to CounterState:

export const initialState = {
  count: 10
};

export const actions = {
  decrement: amount => state => ({ count: state.count - amount })
};

const CounterButton = () => (
  <CounterState initialState={initialState} actions={actions}>
    {({ decrement }) => <button onClick={() => decrement(1)}>Decrement</button>}
  </CounterState>
);

Those new members will work even if you use context.

Global initial state

It's possible to pass initialState to Provider:

const initialState = {
  counter1: {
    count: 10
  }
};

const App = () => (
  <Provider initialState={initialState}>
    ...
  </Provider>
);

This way, all State with context="counter1" will start with { count: 10 }

Note: while using context, only the initialState of the first State in the tree will be considered. Provider will always take precedence over State.

State in lifecycle methods

As stated in the official docs, to access state in lifecycle methods you can just pass the state down as a prop to another component and use it just like another prop:

class CounterButton extends React.Component {
  componentDidMount() {
    this.props.state.increment(1);
  }

  render() {
    const { increment } = this.props.state;
    return <button onClick={() => increment(1)}>Increment</button>;
  }
}

export default props => (
  <CounterState context="counter1">
    {state => <CounterButton {...props} state={state} />}
  </CounterState>
);

Another alternative is to use https://github.com/reactions/component:

import Component from "@reactions/component";

const CounterButton = () => (
  <CounterState context="counter1">
    {({ increment }) => (
      <Component didMount={() => increment(1)}>
        <button onClick={() => increment(1)}>Increment</button>
      </Component>
    )}
  </CounterState>
);

Testing

actions and selectors are pure functions. Testing is pretty straightfoward:

import { initialState, actions, selectors } from "./CounterState";

test("initialState", () => {
  expect(initialState).toEqual({ count: 0 });
});

test("actions", () => {
  expect(actions.increment(1)({ count: 0 })).toEqual({ count: 1 });
  expect(actions.increment(-1)({ count: 1 })).toEqual({ count: 0 });
});

test("selectors", () => {
  expect(selectors.getParity()({ count: 0 })).toBe("even");
  expect(selectors.getParity()({ count: 1 })).toBe("odd");
});

API

Provider

Properties

  • children React.Node
  • initialState Object?

State

Properties

Contributing

If you find some bug, please create an issue providing instructions to reproduce it. It's always very appreciable if you find the time to fix it. In this case, please submit a PR.

If you're a beginner, it'll be a pleasure to help you contribute. See the beginner's guide to contributing to a GitHub project.

Make sure to install dependencies (yarn or npm install) and to lint and test the code before submitting the PR (yarn lint && yarn test).

TODO

  • Side effects / async actions (#1)
  • Middlewares? (create an issue if you find a use case for this)
  • Debugger/devtools

License

MIT © Diego Haz

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.