All Projects → tannerlinsley → react-state

tannerlinsley / react-state

Licence: other
React-State - Superpowers for managing local and reusable state in React

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to react-state

Contextism
😍 Use React Context better.
Stars: ✭ 141 (+907.14%)
Mutual labels:  state-management, state
vuse-rx
Vue 3 + rxjs = ❤
Stars: ✭ 52 (+271.43%)
Mutual labels:  state-management, state
Redux Rs
📦 A Rust implementation of Redux.
Stars: ✭ 158 (+1028.57%)
Mutual labels:  state-management, state
react-globally
Gives you setGlobalState, so you can set state globally
Stars: ✭ 22 (+57.14%)
Mutual labels:  state-management, state
Getx pattern
Design pattern designed to standardize your projects with GetX on Flutter.
Stars: ✭ 225 (+1507.14%)
Mutual labels:  state-management, state
Pure Store
A tiny immutable store with type safety.
Stars: ✭ 133 (+850%)
Mutual labels:  state-management, state
Hydrated bloc
An extension to the bloc state management library which automatically persists and restores bloc states.
Stars: ✭ 181 (+1192.86%)
Mutual labels:  state-management, state
Vue State Store
📮 VSS (Vue State Store) - Vue State Management (with Publish & Subscribe pattern)
Stars: ✭ 128 (+814.29%)
Mutual labels:  state-management, state
React Organism
Dead simple React state management to bring pure components alive
Stars: ✭ 219 (+1464.29%)
Mutual labels:  state-management, state
React Easy State
Simple React state management. Made with ❤️ and ES6 Proxies.
Stars: ✭ 2,459 (+17464.29%)
Mutual labels:  state-management, state
enform
Handle React forms with joy 🍿
Stars: ✭ 38 (+171.43%)
Mutual labels:  state-management, state
Xstate
State machines and statecharts for the modern web.
Stars: ✭ 18,300 (+130614.29%)
Mutual labels:  state-management, state
Swiftdux
Predictable state management for SwiftUI applications.
Stars: ✭ 130 (+828.57%)
Mutual labels:  state-management, state
Freactal
Clean and robust state management for React and React-like libs.
Stars: ✭ 1,676 (+11871.43%)
Mutual labels:  state-management, state
Stateshot
💾 Non-aggressive history state management with structure sharing.
Stars: ✭ 128 (+814.29%)
Mutual labels:  state-management, state
Mobx Rest
REST conventions for Mobx
Stars: ✭ 164 (+1071.43%)
Mutual labels:  state-management, state
Reworm
🍫 the simplest way to manage state
Stars: ✭ 1,467 (+10378.57%)
Mutual labels:  state-management, state
React Workshop
⚒ 🚧 This is a workshop for learning how to build React Applications
Stars: ✭ 114 (+714.29%)
Mutual labels:  state-management, state
Statefulviewcontroller
Placeholder views based on content, loading, error or empty states
Stars: ✭ 2,139 (+15178.57%)
Mutual labels:  state-management, state
Final Form
🏁 Framework agnostic, high performance, subscription-based form state management
Stars: ✭ 2,787 (+19807.14%)
Mutual labels:  state-management, state

react-state

Superpowers for managing local and reusable state in React

Features

  • 2kb! (minified)
  • No dependencies
  • Ditch repetitive props and callbacks throughout deeply nested components
  • Improved performance via Provider & Connector components
  • Testable and predictable

Demo

Table of Contents

Installation

$ yarn add react-state

Example

import React from 'react'
import { Provider, Connect } from 'react-state'


const Count = ({ count }) => ({
  <span>{count}</span>
}
// Use Connect to subscribe to values from the Provider state
const ConnectedCount = Connect(state => ({
  count: state.count
}))(Count)

// Every Connected component can use the 'dispatch' prop
// to update the Provider's store
const Increment = ({ dispatch }) => ({
  <button
    // 'dispatch' takes a function that receives the
    // current provider state and returns a new one.
    onClick={() => dispatch(state => ({
      ...state,
      count: state.count + 1 // Immutable is best for performance :)
    }))}
  >
    Increment Count
  </button>
}
const ConnectedIncrement = Connect()(Increment)

const Demo = () => (
  <div>
    <ConnectedCount />
    <ConnectedIncrement />
  </div>
)

// A Provider is a new instance of state for all nodes inside it
export default Provider(Demo)

Provider

The Provider higher-order component creates a new state that wraps the component you pass it. You can nest Providers inside each other, and when doing so, Connected components inside them will connect to the nearest parent Provider. You can also give Providers an initial state in an optional config object.

Creating a Provider
const ProviderWrappedComponent = Provider(MyComponent);
Initial State
const ProviderWrappedComponent = Provider(MyComponent, {
  // the initial state of the provider
  initial: {
    foo: 1,
    bar: "hello"
  }
});
Passing props as state

Any props you pass to a Provider will be merged with the state and overwrite any same-key values.

<ProviderWrappedComponent foo={1} bar="hello" />
Programatic Control

If you ever need to programmatically dispatch to a provider, you can use a ref!

<ProviderWrappedComponent
  ref={provider => {
    provider.dispatch;
  }}
/>

Connect

The Connect higher-order component subscribes a component to any part of the nearest parent Provider, and also provides the component the dispatch prop for updating the state.

Subscribing to state

To subscribe to a part of the provider state, we use a function that takes the state (and component props) and returns a new object with parts of the state you're interested in. Any time the values of that object change, your component will be updated! (There is no need to return props that already exist on your component. The 'props' argument is simply there as an aid in calculating the state you need to subscribe to)

class MyComponent extends Component {
  render() {
    return (
      <div>
        // This 'foo' prop comes from our Connect function below
        <div>{this.props.foo}</div>
      </div>
    );
  }
}
const MyConnectedComponent = Connect(state => {
  return {
    foo: state.foo // Any time 'foo' changes, our component will update!
  };
});
Using the dispatcher

Every connected component receives a 'dispatch' prop. You can use this 'dispatch' function to update the provider state. Just dispatch a function that takes the current state and returns a new version of the state. It's very important to make changes using immutability and also include any unchanged parts of the state. What you return will replace the entire state!

class MyComponent extends Component {
  render() {
    return (
      <div>
        <button
          onClick={this.props.dispatch(state => {
            return {
              ...state, // include unchanged parts of the state
              foo: Math.ceil(Math.random() * 10) // update our new random 'foo' value
            };
          })}
        >
          Randomize Foo
        </button>
      </div>
    );
  }
}
const MyConnectedComponent = Connect()(MyComponent);
Memoization and Selectors

If you need to subscribe to computed or derived data, you can use a memoized selector. This functions exactly as it does in Redux. For more information, and examples on usage, please refer to Redux - Computing Derived Data

class MyComponent extends Component {
  render() {
    return (
      <div>
        <div>{this.props.computedValue}</div>
      </div>
    );
  }
}
const MyConnectedComponent = Connect((state, props) => {
  return {
    computedValue: selectMyComputedValue(state, props)
  };
});
Dispatch Meta

Any time you dispatch, you have the option to send through a meta object. This is useful for middlewares, hooks, and other optimization options throughout react-state.

class MyComponent extends Component {
  render () {
    return (
      <div>
        <button
          onClick={this.props.dispatch(state => ({
            ...state,
            foo: Math.Ceil(Math.random() * 10)
          }, {
            // you can use any object as meta
            mySpecialValue: 'superSpecial'
          })}
        >
          Randomize Foo
        </button>
      </div>
    )
  }
}
const MyConnectedComponent = Connect()(MyComponent)
Connect Config

Connect can be customized for performance and various other enhancments:

  • pure: Boolean: Defualts to true. When true the component will only rerender when the resulting props from the selector change in a shallow comparison.
  • filter(oldState, newState, meta): Only run connect if this function returns true. Useful for avoiding high-velocity dispatches or general performance tuning.
  • statics{}: An object of static properties to add to the connected component's class.
class MyComponent extends Component { ... }
const MyConnectedComponent = Connect(
  state => {...},
  {
    // Using the following 'filter' function, this Connect will not run if 'meta.mySpecialValue === 'superSpecial'
    filter: (oldState, newState, meta) => {
      return meta.mySpecialValue ? meta.mySpecialValue !== 'superSpecial' : true
    },

    // The Connected component class will also gain these statics
    statics: {
      defaultProps: {
        someProp: 'hello!'
      }
    }
  }
)(MyComponent)

Contributing

To suggest a feature, create an issue if it does not already exist. If you would like to help develop a suggested feature follow these steps:

  • Fork this repo
  • $ yarn
  • $ yarn run storybook
  • Implement your changes to files in the src/ directory
  • View changes as you code via our React Storybook localhost:8000
  • Make changes to stories in /stories, or create a new one if needed
  • Submit PR for review

Scripts

  • $ yarn run storybook Runs the storybook server
  • $ yarn run test Runs the test suite
  • $ yarn run prepublish Builds for NPM distribution
  • $ yarn run docs Builds the website/docs from the storybook for github pages
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].