1.0.0 • Published 5 years ago

react-state-patterns v1.0.0

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

react-state-patterns

npm version License CircleCI

Tiny utility package for easily creating reusable implementations of React state provider patterns.

🚀 react-state-patterns makes it easy to (and reduces boilerplate) create implementations of common React state provider patterns.

⚠️ Powered by React Hooks under the hood. (This library has a peer dependency on react: ^16.8.0)

Getting Started

Install

npm install react-state-patterns --save

Creating State Patterns

Directly From Hook

import useProviders, { hookSchema } from '@procore/react-state-patterns';

// Create the state patterns
const Counter = statePatterns(props => {
  const [count, setCount] = useState(props.initialValue || 0);
  const handlers = {
    incrementBy: value => setCount(count + value),
    decrementBy: value => setCount(count - value)
  };
  // hookSchema(...)
  //    => { counter: { state: { count: 0 }, handlers: { incrementBy: (v) => {...}, decrementBy: (v) => {...} } } }
  return hookSchema({ count: count }, handlers, "counter");
});

// Counter = { useHook, withState, State, Provider, Consumer }

Using useStateHook util

useStateHook API Docs

import useProviders, { useStateHook } from '@procore/react-state-patterns';

// Create the state patterns
const Counter = useProviders(
  useStateHook(
    (props) => ({ count: props.initialValue || 0 }),
    {
      incrementBy: state => value => ({ ...state, count: state.count + value }),
      decrementBy: state => value => ({ ...state, count: state.count - value })
    },
    "counter"
  )
);

// Counter = { useHook, withState, State, Provider, Consumer }

Use the patterns

Decorator Pattern

const Displayer = ({ counter: { state, handlers }}) => (
  <React.Fragment>
    <div>{state.count}</div>
    <button onClick={() => handlers.decrementBy(1)}>Decrement</button>
    <button onClick={() => handlers.incrementBy(1)}>Increment</button>
  </React.Fragment>
);

const StatefulDisplayer = Counter.withState(Displayer);

const rootElement = document.getElementById("root");
ReactDOM.render(<StatefulDisplayer initialValue={5} />, rootElement);

Render Prop Pattern

const Displayer = (props) => (
  <Counter.State initialValue={5}>
    {({ counter: { state, handlers } }) => (
      <React.Fragment>
        <div>{state.count}</div>
        <button onClick={() => handlers.decrementBy(1)}>Decrement</button>
        <button onClick={() => handlers.incrementBy(1)}>Increment</button>
      </React.Fragment>
    )}
  </Counter.State>
);

Context Provider/Consumer Pattern

const Displayer = (props) => (
  <Counter.Provider initialValue={5}>
    <Counter.Consumer>
      {({ counter: { state, handlers } }) => (
        <React.Fragment>
          <div>{state.count}</div>
          <button onClick={() => handlers.decrementBy(1)}>Decrement</button>
          <button onClick={() => handlers.incrementBy(1)}>Increment</button>
        </React.Fragment>
      )}
    </Counter.Consumer>
  </Counter.Provider>
);

Custom Hook Pattern

const Displayer = (props) => {
  const { counter: { state, handlers } } = Counter.useHook({ initialValue: 5 });

  return (
    <React.Fragment>
      <div>{state.count}</div>
      <button onClick={() => handlers.decrementBy(1)}>Decrement</button>
      <button onClick={() => handlers.incrementBy(1)}>Increment</button>
    </React.Fragment>
  );
};

Code Style Guides

code style: prettier

Prettier is run as a pre-commit hook to automatically modify staged .js and .jsx files to adhere to base code style rules defined in the .prettierrc.

Eslint is also used as an in-editor linter, so be sure to install an appropriate Eslint Plugin for your editor of choice. Prettier rules are setup to take precedence and override any conflicting eslint rules.

1.0.0

5 years ago

0.4.0

5 years ago

0.3.4

5 years ago

0.3.3

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.7

5 years ago

0.1.6

5 years ago

0.1.5

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago