All Projects → aweary → React Copy Write

aweary / React Copy Write

Licence: mit
✍️ Immutable state with a mutable API

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to React Copy Write

immerx-state
Reactive, fractal and no-nonsense state management with Immer
Stars: ✭ 19 (-98.95%)
Mutual labels:  state, immer
boutique
Immutable data storage
Stars: ✭ 44 (-97.57%)
Mutual labels:  immutable, state
react-immer-hooks
Easy immutability in React Hooks with Immer.
Stars: ✭ 45 (-97.51%)
Mutual labels:  immer, copy-on-write
Easy Peasy
Vegetarian friendly state for React
Stars: ✭ 4,525 (+150%)
Mutual labels:  immutable, immer
Bbx
𝕓𝕓𝕩 是一个极其简单高效的 React 状态管理方式
Stars: ✭ 134 (-92.6%)
Mutual labels:  state
Apple Basket Redux
🍎 苹果篮子,一个微型的redux/mobx演示(附多版本)
Stars: ✭ 125 (-93.09%)
Mutual labels:  immutable
Typed
The TypeScript Standard Library
Stars: ✭ 124 (-93.15%)
Mutual labels:  immutable
Test State
Scala Test-State.
Stars: ✭ 119 (-93.43%)
Mutual labels:  state
Immer
Postmodern immutable and persistent data structures for C++ — value semantics at scale
Stars: ✭ 1,935 (+6.91%)
Mutual labels:  immutable
Contextism
😍 Use React Context better.
Stars: ✭ 141 (-92.21%)
Mutual labels:  state
Pure Store
A tiny immutable store with type safety.
Stars: ✭ 133 (-92.65%)
Mutual labels:  state
List
🐆 An immutable list with unmatched performance and a comprehensive functional API.
Stars: ✭ 1,604 (-11.38%)
Mutual labels:  immutable
Designpatterns
🔑Elements of Reusable Object-Oriented Software🔓is a software engineering book describing software design patterns. The book's authors are Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides with a foreword by Grady Booch.
Stars: ✭ 134 (-92.6%)
Mutual labels:  state
Dictomaton
Finite state dictionaries in Java
Stars: ✭ 124 (-93.15%)
Mutual labels:  state
Monolite
Statically-typed structural-sharing tree modifier
Stars: ✭ 144 (-92.04%)
Mutual labels:  immutable
React Cloud Music
React 16.8打造精美音乐WebApp
Stars: ✭ 1,722 (-4.86%)
Mutual labels:  immutable
Optics Ts
Type-safe, ergonomic, polymorphic optics for TypeScript
Stars: ✭ 132 (-92.71%)
Mutual labels:  immutable
Android Statefullayout
A custom Android ViewGroup to display different states of screen (CONTENT, PROGRESS, OFFLINE, EMPTY, etc.)
Stars: ✭ 140 (-92.27%)
Mutual labels:  state
Swiftdux
Predictable state management for SwiftUI applications.
Stars: ✭ 130 (-92.82%)
Mutual labels:  state
Stateshot
💾 Non-aggressive history state management with structure sharing.
Stars: ✭ 128 (-92.93%)
Mutual labels:  state

react-copy-write

goat

An immutable React state management library with a simple mutable API, memoized selectors, and structural sharing. Powered by Immer.

Overview

The benefits of immutable state are clear, but maintaining that immutable state can sometimes be burdensome and verbose: updating a value more than one or two levels deep in your state tree can require lots of object/array spreading, and it's relatively easy to accidentally mutate something.

react-copy-write lets you use straightforward mutations to update an immutable state tree, thanks to Immer. Since Immer uses the copy-on-write technique to update immutable values, we get the benefits of structural sharing and memoization. This means react-copy-write not only lets you use simple mutations to update state, but it's also very efficient about re-rendering.

Documentation

react-copy-write is currently under-going significant API changes as it's tested in a production environment. Most documentation has been removed until we arrive at a stable API. Below you will find a bare-bones API reference that should get you started.

createState

The default export of the package. Takes in an initial state object and returns a collection of components and methods for reading, rendering, and updating state.

import createState from 'react-copy-write'

const {
  Provider,
  Consumer,
  createSelector,
  mutate,
} = createState({name: 'Brandon' });

Provider

The Provider component provides state to all the consumers. All Consumer instances associated with a given provider must be rendered as children of the Provider.

const App = () => (
  <Provider>
    <AppBody />
  </Provider>
)

If you need to initialize state from props you can use the initialState prop to do so. Note that it only initializes state, updating initialState will have no effect.

const App = ({user}) => (
  <Provider initialState={{name: user.name }}>
    <AppBody />
  </Provider>
)

Consumer

A Consumer lets you consume some set of state. It uses a render prop as a child for accessing and rendering state. This is identical to the React Context Consumer API.

const Avatar = () => (
  <Consumer>
   {state => (
     <img src={state.user.avatar.src} />
   )}
  </Consumer>
)

The render callback is always called with a tuple of the observed state, using an array. By default that tuple contains one element: the entire state tree.

Selecting State

If a Consumer observes the entire state tree then it will update anytime any value in state changes. This is usually not what you want. You can use the select prop to select a set of values from state that a Consumer depends on.

const Avatar = () => (
  <Consumer select={[state => state.user.avatar.src]}>
    {src => <img src={src} />}
  </Consumer>
)

Now the Avatar component will only re-render if state.user.avatar.src changes. If a component depends on multiple state values you can just pass in more selectors.

const Avatar = () => (
  <Consumer select={[
    state => state.user.avatar.src,
    state => state.theme.avatar,
  ]}>
    {(src, avatarTheme) => <img src={src} style={avatarTheme} />}
  </Consumer>
)

Updating State

createState also returns a mutate function that you can use to make state updates.

const {mutate, Consumer, Provider} = createState({...})

Mutate takes a single function as an argument, which will be passed a "draft" of the current state. This draft is a mutable copy that you can edit directly with simple mutations

const addTodo = todo => {
  mutate(draft => {
    draft.todos.push(todo);
  })
}

You don't have to worry about creating new objects or arrays if you're only updating a single item or property.

const updateUserName = (id, name) => {
  mutate(draft => {
    // No object spread required 😍
    draft.users[id].name = name;
    draft.users[id].lastUpdate = Date.now();
  })
}

Check out the Immer docs for more information.

Since mutate is returned by createState you can call it anywhere. If you've used Redux you can think of it like dispatch in that sense.

Optimized Selectors

createState also returns a createSelector function which you can use to create an optimized selector. This selector should be defined outside of render, and ideally be something you use across multiple components.

const selectAvatar = createSelector(state => state.user.avatar.src);

You can get some really, really nice speed if you use this and follow a few rules:

Don't call createSelector in render.

🚫

const App = () => (
  // Don't do this 
  <Consumer select={[createSelector(state => state.user)]}>
    {...}
  </Consumer>
)

👍

// Define it outside of render!
const selectUser = createSelector(state => state.user);
const App = () => (
  <Consumer select={[selectUser]}>
    {...}
  </Consumer>
)

Avoid mixing optimized and un-optimized selectors

🚫

const selectUser = createSelector(state => state.user);
const App = () => (
  // This isn't terrible but the consumer gets de-optimized so
  // try to avoid it
  <Consumer select={[selectUser, state => state.theme]}>
    {...}
  </Consumer>
)

👍

const selectUser = createSelector(state => state.user);
const selectTheme = createSelector(state => state.theme);
const App = () => (
  <Consumer select={[selectUser, selectTheme]}>
    {...}
  </Consumer>
)
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].