Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
React Tetris | 7,302 | 3 months ago | 4 | June 22, 2018 | 10 | JavaScript | ||||
Use React, Redux, Immutable to code Tetris. 🎮 | ||||||||||
Easy Peasy | 4,900 | 37 | 50 | 20 days ago | 254 | September 17, 2022 | 26 | mit | JavaScript | |
Vegetarian friendly state for React | ||||||||||
Pepperoni App Kit | 4,640 | a month ago | 4 | March 24, 2017 | 67 | mit | JavaScript | |||
Pepperoni - React Native App Starter Kit for Android and iOS | ||||||||||
Vue Tetris | 2,559 | 4 months ago | 6 | mit | JavaScript | |||||
Use Vue, Vuex to code Tetris.使用 Vue, Vuex 做俄罗斯方块 | ||||||||||
Redux Immutable | 1,880 | 3,724 | 517 | a year ago | 33 | March 14, 2017 | 9 | other | TypeScript | |
redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state. | ||||||||||
React Cloud Music | 1,852 | 8 months ago | 34 | mit | JavaScript | |||||
React 16.8打造精美音乐WebApp | ||||||||||
React Copy Write | 1,804 | 4 years ago | 18 | mit | JavaScript | |||||
✍️ Immutable state with a mutable API | ||||||||||
React Awesome Query Builder | 1,491 | 5 | 8 | 5 days ago | 144 | March 15, 2022 | 128 | mit | JavaScript | |
User-friendly query builder for React | ||||||||||
Freezer | 1,252 | 121 | 36 | 4 years ago | 31 | August 02, 2018 | 12 | mit | JavaScript | |
A tree data structure that emits events on updates, even if the modification is triggered by one of the leaves, making it easier to think in a reactive way. | ||||||||||
Omniscient | 1,196 | 88 | 10 | 4 years ago | 21 | October 19, 2017 | 11 | JavaScript | ||
A library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data for js |
An immutable React state management library with a simple mutable API, memoized selectors, and structural sharing. Powered by Immer.
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.
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.
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>
)
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.
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:
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>
)
🚫
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>
)