1.1.1 • Published 6 years ago

thram-stateless v1.1.1

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

thram-stateless

React components for Application and Component state management using render props and Context API

NPM JavaScript Style Guide

Install

npm install --save thram-stateless

Components

<Stateless />

Add dynamic behaviour to your components without using state.

proptypedescription
valueObjectComponent value
eventsObjectbeforeMount, afterMount, beforeChange, afterChange
reducerfunctionReducer function

<StoreProvider />

Add dynamic behaviour to a group of components using a store that can be consumed by <Store />.

proptypedescription
valueObjectComponent value
eventsObjectbeforeMount, afterMount, beforeChange, afterChange
reducerfunctionReducer function
persistorObjectPersistor API to perist data after change and rehydrate

<Store />

Store consumer.

proptypedescription
stateStringKey of the value you want to connect in the store
reducerfunctionReducer function

Usage

Stateless

import React from 'react';
import { Stateless } from 'thram-stateless';

const DisplayDropDown = ({ isOpened, toggle }) => (
  <div>
    <div>
      Menu <i onClick={toggle}>{isOpened ? '👆' : '👇'}</i>
    </div>
    {isOpened && (
      <ul>
        <li>Menu 1</li>
        <li>Menu 2</li>
        <li>Menu 3</li>
      </ul>
    )}
  </div>
);

const DropDown = () => (
  <Stateless value={{ isOpened: false }}>
    {({ value, change }) => (
      <DisplayDropDown
        isOpened={value.isOpened}
        toggle={() => change({ isOpened: !value.isOpened })}
      />
    )}
  </Stateless>
);

Application Store

StoreProvider implements Sateless under the hood so they have similar APIs.

import React, { PureComponent } from 'react';
import { StoreProvider, Store } from 'thram-stateless';

const AppCounter = () => (
  <Store state="counter">
    {({ value, change }) => (
      <div>
        <h2>{value}</h2>
        <button onClick={() => change(value + 1)}>Button</button>
      </div>
    )}
  </Store>
);

class App extends PureComponent {
  render = () => (
    <StoreProvider value={{ counter: 6 }}>
        <Counter />
      </StoreProvider>,
  );
}

Events

StoreProvider and Stateless has a very simple event lifecyle: beforeMount, afterMount, beforeChange, afterChange

const App = () => (
  <StoreProvider
    events={{
      beforeMount: value => {
        /* .. */
      },
      afterMount: (value, change) => {
        /* ... */
      },
      beforeChange: (nextValue, prevValue) => {
        /* ... */
      },
      afterChange: (nextValue, prevValue) => {
        /* ... */
      },
    }}
  >
    <Counter />
  </StoreProvider>
);
const DropDown = () => (
  <Stateless
    value={{ isOpened: false }}
    events={{
      beforeMount: value => {
        /* .. */
      },
      afterMount: (value, change) => {
        /* ... */
      },
      beforeChange: (nextValue, prevValue) => {
        /* ... */
      },
      afterChange: (nextValue, prevValue) => {
        /* ... */
      },
    }}
  >
    {({ value, change }) => (
      <DisplayDropDown
        isOpened={value.isOpened}
        toggle={() => change({ isOpened: !value.isOpened })}
      />
    )}
  </Stateless>
);

Reducer

StoreProvider, Store and Stateless can all handle the reducer pattern to reduce the value before update:

const ReducedStoreApp = () => (
  <StoreProvider reducer={(state, value) => ({ counter: value.counter + 1 })}>
    <Counter />
  </StoreProvider>
);
const ReducedGlobalCounter = () => (
  <Store state="counter" reducer={(state, value) => value + 1}>
    {({ value, change }) => (
      <Display value={value} onClick={() => change(value + 1)} />
    )}
  </Store>
);
const ReducedCounter = () => (
  <Stateless
    value={{ counter: 1 }}
    reducer={(state, value) => ({ counter: value.counter + 1 })}
  >
    {({ value, change }) => (
      <Display
        value={value.counter}
        onClick={() => change({ counter: value.counter + 1 })}
      />
    )}
  </Stateless>
);

Persistor

You can pass a Persistor API to the StoreProvider to persist/rehydrate the data.

You can use our simple implementation createPeristor that uses localStorage/sessionStorage or you can implement yours.

The Persistor API should have the following structure:

{
  get: () => { /* To rehydrate */ },
  set: () => { /* To persist data */ },
  remove: () => { /* To remove a value */ },
  clear: () => { /* To destroy the persisted data */ },
}

Example:

import React, { PureComponent } from 'react';
import { StoreProvider, Store, createPersistor } from 'thram-stateless';

const persistor = createPersistor('app');

const AppCounter = () => (
  <Store state="counter">
    {({ value, change }) => (
      <div>
        <h2>{value}</h2>
        <button onClick={() => change(value + 1)}>Button</button>
      </div>
    )}
  </Store>
);

class App extends PureComponent {
  render = () => (
    <StoreProvider persistor={persistor} value={{ counter: 6 }}>
      <Counter />
    </StoreProvider>,
  );
}

TODO

  • Ask for feedback!

License

MIT © Thram