Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

✍️ Immutable state with a mutable API

License

NotificationsYou must be signed in to change notification settings

aweary/react-copy-write

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

75 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

goat

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

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 toImmer. Since Immer uses thecopy-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.

importcreateStatefrom'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.

constApp=()=>(<Provider><AppBody/></Provider>)

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

constApp=({user})=>(<ProviderinitialState={{name:user.name}}><AppBody/></Provider>)

Consumer

A Consumer lets youconsume some set of state. It uses arender prop as a child for accessing and rendering state. This is identical to theReact Context Consumer API.

constAvatar=()=>(<Consumer>{state=>(<imgsrc={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 anytimeany value in state changes. This is usually not what you want. You can use theselect prop to select a set of values from state that a Consumer depends on.

constAvatar=()=>(<Consumerselect={[state=>state.user.avatar.src]}>{src=><imgsrc={src}/>}</Consumer>)

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

constAvatar=()=>(<Consumerselect={[state=>state.user.avatar.src,state=>state.theme.avatar,]}>{(src,avatarTheme)=><imgsrc={src}style={avatarTheme}/>}</Consumer>)

Updating State

createState also returns amutate 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

constaddTodo=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.

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

Check outthe Immer docs for more information.

Sincemutate is returned bycreateState you can call it anywhere. If you've used Redux you can think of it likedispatch in that sense.

Optimized Selectors

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

constselectAvatar=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 callcreateSelector in render.

🚫

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

👍

// Define it outside of render!constselectUser=createSelector(state=>state.user);constApp=()=>(<Consumerselect={[selectUser]}>{...}</Consumer>)

Avoid mixing optimized and un-optimized selectors

🚫

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

👍

constselectUser=createSelector(state=>state.user);constselectTheme=createSelector(state=>state.theme);constApp=()=>(<Consumerselect={[selectUser,selectTheme]}>{...}</Consumer>)

About

✍️ Immutable state with a mutable API

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors13


[8]ページ先頭

©2009-2025 Movatter.jp