UNPKG

react-3ducks

Version:

Simple state management library for React

130 lines (89 loc) 4.86 kB
# react-3ducks :duck: :hatched_chick: :hatching_chick: A simple react global state management solution - [Installation](#installation) - [Why](#why) - [Example](#example) - [API](#api) - [Contributing](#contributing) ## Installation ``` npm install react-3ducks ``` ## Why Redux is the current prevailing solution to manage global state in React apps. However, there are a few shortcomings to it that this project attempts to address. Some of them are as follows - **Encapsulation**: Redux by convention has only one global store and it encapsulate only data. The behavior is fragmented between actions, action creators, reducers, epics, sagas, thunks etc. **react-3ducks** encourages and facilitates creation of multiple stores for various concerns in the application and also allows behavior encapsulation in the stores. - **Asynchronous Behavior**: Redux has no built in way of handling asynchronous actions. **react-3ducks** fully supports asynchronous behavior through regular ```async/await``` or ```Promise``` based semantics that are already known and loved. - **Complexity**: Its hard to quickly grasp what's going on in a Redux app. Mainly because of the fragmentation. There are many files and its not obvious what's going on where. **react-3ducks** addresses this by keeping all related logic and data together. - **Boilerplate**: The amount of boilerplate code in Redux apps is just too much. **react-3ducks** allows for very terse declaration and definition of both state and behavior. ## Example This is a bare minimum example, Check out [this](https://stackblitz.com/github/smakazmi/react-3ducks/tree/master/examples/todos) for a (relatively) more elaborate one ```jsx //Imports import React from "react"; import ReactDOM from "react-dom"; import StateStore, {root, container} from "react-3ducks"; //Store class class CounterStore extends StateStore { // increment action increment = () => { this.setState({count: this.state.count + 1}); } // decrement action decrement = () => { this.setState({count: this.state.count - 1}); } } //Components const Button = ({onClick, text}) => ( <button onClick={onClick}>{text}</button> ) const Label = ({text}) => ( <span>{text}</span> ) //Containers const IncrementButton = container(Button, ({counterStore, props}) => ({ onClick: counterStore.increment, text: "+" })); const DecrementButton = container(Button, ({counterStore}) => ({ onClick: counterStore.decrement, text: "-" })); const CounterDisplay = container(Label, ({counterStore}) => ({ text: counterStore.state.count })); //Store instance const counterStore = new CounterStore({count: 0}); //Root const App = root(() => ( <div> <IncrementButton/> <CounterDisplay/> <DecrementButton/> </div> ), {counterStore}) //Render ReactDOM.render(<App/>, document.getElementById("root")); ``` See [this example](https://stackblitz.com/edit/react-3ducks-counter-sample) in action ## API Time to introduce the three ducks (i.e. **```StateStore```**, **```root```**, and **```container```**) in **react-3ducks** ### ```StateStore``` class Encapsulates state and behavior. Should be extended to create separate specialized stores for e.g. CartStore, ProductsStore, AuthStore etc. #### ```setState(newState)``` Method ```setState``` works exactly as it does in React components. It expects a partial object with state changes and merges it into the existing state. #### ```state``` Property ```state``` also works exactly as it does in React components. Allows readonly access to the current state. ### ```root(Component, {store1, store2, ...})``` Higher Order Component The **```root```** HOC accepts a Component and an object containing any stores that should be made available to the **```container```** components under **```Component```** ### ```container(Component, mapToProps?)``` Higher Order Component The **```container```** HOC passes stores as props to the **```Component```**. Alternatively, if its passed a second (optional) parameter i.e. **```mapToProps```**, it allows to map store state and behavior to props selectively. #### ```mapToProps``` This is a selector function that can be optionally passed as a second parameter to the **```container```** HOC to allow for selective mapping of store state and behavior to props passed to the wrapped **```Component```**. Its defined as ```js function(stores, ownProps) ``` In the first parameter its passed an object containing all the stores connected to the **```root```** component. The second parameter contains the props passed to the wrapper component created by the **```container```** HOC. Its expected to return a plain object with prop names as keys, mapped to state or behavior ## Contributing Contributions are very welcome. Just send a PR against the master branch or open a new issue. Thanks!