react-vessel
A different approach for managing your state in react
Last updated 4 months ago by nepjua .
MIT · Repository · Original npm · Tarball · package.json
$ cnpm install react-vessel 
SYNC missed versions from official npm registry.

React Vessel

npm Codecov CircleCI

A different approach for managing your state in react. Build your applications with composing dynamic reducers through JSX api.

???? CodeSandbox demos ????
Counter

Installation

Install react-vessel:

npm install react-vessel

or with yarn:

yarn add react-vessel

What you can do with it

You can write a simple counter like this

Here is the simplest thing you can do with a vessel.

import React from 'react';
import { Vessel, Reducer } from 'react-vessel';

function Counter({ name }) {
  const { dispatch } = useParentVessel();
  const count = useParentState(name, 0);

  return (
    <div>
      <Reducer model={name} action="increment" reducer={(state = 0) => state + 1} />
      <Reducer model={name} action="decrement" reducer={(state = 0) => state - 1} />
      <div>{count}</div>
      <button type="button" onClick={() => dispatch({ type: 'count/increment' })}>
        Increment
      </button>
      <button type="button" onClick={() => dispatch({ type: 'count/decrement' })}>
        Decrement
      </button>
    </div>
  );
}

function App() {
  return (
    <Vessel>
      <Counter name="counter1" />
      <Counter name="counter2" />
    </Vessel>
  );
}

Notice how you could easily reuse the component.

Above code will produce following state in your vessel:

{
  "counter1": 0,
  "counter2": 0
}

You can access this state anywhere in your application

function MyComponent() {
  const count = useParentState('counter1', 0);
  return <div>{count}</div>;
}

Or you can use a component with render props if you prefer that:

function MyComponent() {
  return <WithVessel select="counter1" render={(count, { state, dispatch }) => {
    return <div>{count}</div>
  }}>
}

You can add/remove reducers dynamically

function MyComponent() {
  const [incrementEnabled, setIncrementEnabled] = useState();

  return (
    <React.Fragment>
      {incrementEnabled && (
        <Reducer model="my-counter" action="increment" reducer={(state = 0) => state + 1} />
      )}
      <Reducer model="my-counter" action="decrement" reducer={(state = 0) => state - 1} />
      <button type="button" onClick={() => setIncrementEnabled(!incrementEnabled)}>
        Enable/Disable Increment
      </button>
    </React.Fragment>
  );
}

You can combine multiple reducers inside a Model

<Model name="my-counter">
  <Reducer action="increment" reducer={(state = 0) => state + 1} />
  <Reducer action="decrement" reducer={(state = 0) => state - 1} />
</Model>

You can build a simple FormInput

function FormInput({ name, render }) {
  const value = useVesselState(`${name}.value`);
  const { dispatch } = useVesselDispatch();

  function onChange(payload) {
    dispatch({ type: `${name}/change`, payload });
  }

  return (
    <React.Fragment>
      <Reducer
        model={name}
        action="change"
        reducer={(state, payload) => ({ ...state, value: payload })}
      />
      {render({ onChange, value })}
    </React.Fragment>
  );
}

function TextInput({ name }) {
  return (
    <FormInput
      name={name}
      render={({ onChange, value }) => (
        <input value={value} onChange={e => onChange(e.target.value)} />
      )}
    />
  );
}

function App() {
  return (
    <Vessel>
      <TextInput name="smart-input" />

      <WithVessel
        select="input.value"
        render={(value, { state, dispatch }) => {
          return <p>{value}</p>;
        }}
      />
    </Vessel>
  );
}

You can write effects that runs after an action

function ValidateUsername() {
  const { dispatch } = useParentVessel();
  return (
    <Reducer model="username" action="validate-suc" reducer={(state) => ({ ...state, error: null })} />
    <Reducer model="username" action="validate-err" reducer={(state, payload) => ({ ...state, error: payload })} />
    <Effect
      on="username/changed"
      run={async action => {
        try {
          await api.validateUsername(action.payload);
          dispatch({ type: 'username/validate-suc' });
        } catch (err) {
          dispatch({ type: 'username/validate-err', payload: err.message });
        }
      }}
    />
  );
}

function App() {
  return (
    <Vessel>
      <TextInput name="username" />

      <ValidateUsername />
    </Vessel>
  );
}

Current Tags

  • 0.2.2                                ...           latest (4 months ago)

3 Versions

  • 0.2.2                                ...           4 months ago
  • 0.2.1                                ...           4 months ago
  • 0.2.0                                ...           4 months ago
Maintainers (1)
Downloads
Today 0
This Week 3
This Month 3
Last Day 3
Last Week 0
Last Month 0
Dependencies (3)
Dependents (0)
None

Copyright 2014 - 2017 © taobao.org |