pullstate
Version:
Simple state stores using immer and React hooks
137 lines (99 loc) • 5.38 kB
Markdown
<p align="center">
<img src="https://github.com/lostpebble/pullstate/raw/master/graphics/logo-newest.png" alt="Pullstate" />
</p>
### pullstate
> Ridiculously simple state stores with performant retrieval anywhere
> in your React tree using the wonderful concept of React hooks!
* ~7KB minified and gzipped! (excluding Immer and React)
* Built with Typescript, providing a great dev experience if you're using it too
* Uses [immer](https://github.com/mweststrate/immer) for state updates - easily and safely mutate your state directly!
* **NEW** - [Create async actions](https://lostpebble.github.io/pullstate/docs/async-actions-introduction) and use React hooks or `<Suspense/>` to have complete control over their UI states!
_Originally inspired by the now seemingly abandoned library - [bey](https://github.com/jamiebuilds/bey). Although substantially
different now- with Server-side rendering and Async Actions built in! Bey was in turn inspired by
[react-copy-write](https://github.com/aweary/react-copy-write)._
Try out a quick example:
[](https://codesandbox.io/s/myvj8zzypp)
### 🎉 **[New documentation site is live!](https://lostpebble.github.io/pullstate/)**
* [Installation](https://lostpebble.github.io/pullstate/docs/installation)
* [Quick example](https://lostpebble.github.io/pullstate/docs/quick-example)
* [Quick example - Server rendering](https://lostpebble.github.io/pullstate/docs/quick-example-server-rendered)
* [Async Actions](https://lostpebble.github.io/pullstate/docs/async-actions-introduction)
* [Creation](https://lostpebble.github.io/pullstate/docs/async-actions-creating)
* [Usage](https://lostpebble.github.io/pullstate/docs/async-action-use)
* [Async action hooks](https://lostpebble.github.io/pullstate/docs/async-hooks-overview)
---
# **Let's dive right in**
> This is taken directly from [the documentation site](https://lostpebble.github.io/pullstate/docs/quick-example), to give you a quick overview of Pullstate here on github. Be sure to check out the site to learn more.
To start off, install `pullstate`.
```bash
yarn add pullstate
```
## Create a store
Define the first **state store**, by passing an initial state to `new Store()`:
<!--JavaScript-->
```jsx
import { Store } from "pullstate";
export const UIStore = new Store({
isDarkMode: true,
});
```
## Read our store's state
Then, in React, we can start using the state of that store using a simple hook `useState()`:
```tsx
import * as React from "react";
import { UIStore } from "./UIStore";
export const App = () => {
const isDarkMode = UIStore.useState(s => s.isDarkMode);
return (
<div
style={{
background: isDarkMode ? "black" : "white",
color: isDarkMode ? "white" : "black",
}}>
<h1>Hello Pullstate</h1>
</div>
);
};
```
The argument to `useState()` over here (`s => s.isDarkMode`), is a selection function that ensures we select only the state that we actually need for this component. This is a big performance booster, as we only listen for changes (and if changed, re-render the component) on the exact returned values - in this case, simply the value of `isDarkMode`.
---
## Add interaction (update state)
Great, so we are able to pull our state from `UIStore` into our App. Now lets add some basic interaction with a `<button>`:
```tsx
return (
<div
style={{
background: isDarkMode ? "black" : "white",
color: isDarkMode ? "white" : "black",
}}>
<h1>Hello Pullstate</h1>
<button
onClick={() =>
UIStore.update(s => {
s.isDarkMode = !isDarkMode;
})
}>
Toggle Dark Mode
</button>
</div>
);
```
Notice how we call `update()` on `UIStore`, inside which we directly mutate the store's state. This is all thanks to the power of `immer`, which you can check out [here](https://github.com/immerjs/immer).
Another pattern, which helps to illustrate this further, would be to actually define the action of toggling dark mode to a function on its own:
<!--JavaScript-->
```tsx
function toggleMode(s) {
s.isDarkMode = !s.isDarkMode;
}
// ...in our <button> code
<button onClick={() => UIStore.update(toggleMode)}>Toggle Dark Mode</button>
```
Basically, to update our app's state all we need to do is create a function (inline arrow function or regular) which takes the current store's state and mutates it to whatever we'd like the next state to be.
## Omnipresent state updating
Something interesting to notice at this point is that we are just importing `UIStore` directly and running `update()` on it:
```tsx
import { UIStore } from "./UIStore";
// ...in our <button> code
<button onClick={() => UIStore.update(toggleMode)}>Toggle Dark Mode</button>
```
And our components are being updated accordingly. We have freed our app's state from the confines of the component! This is one of the main advantages of Pullstate - allowing us to separate our state concerns from being locked in at the component level and manage things easily at a more global level from which our components listen and react (through our `useStoreState()` hooks).