@runicjs/runic-react
Version:
Tools for working with Runic in React
108 lines (86 loc) • 2.68 kB
Markdown
# Runic
Runic React provides tools for working with Runic in React.
> **Warning**
> Runic React is in its infancy. It's not safe to use in production at this time.
## Roadmap
- [x] Implement `useStore`
- [x] Publish a proper build to NPM (https://www.npmjs.com/package/@runicjs/runic-react)
- [x] Write tests
- [x] Implement `useStores`
- [ ] Test selector that relies on a value from another selector that just changed
- [ ] Test default selector (entire state)
- [ ] Test creating stores dynamically (e.g. in a Context) and destroying them
- [ ] Implement TodoMVC using runic-react
- [ ] Verify that there are no unnecessary rerenders
- [ ] Implement a larger app with more complex state using runic. RealWorld perhaps?
## Usage
### `useStore`
```tsx
import { createStore } from '/runic';
import { useStore } from '/runic-react';
type Counter = {
count: number;
};
export const counterStore = createStore<Counter>({
count: 0,
});
export const increment = () => {
updateState(counterStore, (counter) => {
counter.count++;
});
};
export const decrement = () => {
updateState(counterStore, (counter) => {
counter.count--;
});
};
function Counter() {
// Only re-renders when count changes
const count = useStore(counterStore, (counter) => counter.count);
// "Computed" value
const doubled = useStore(counterStore, (counter) => counter.count * 2);
return (
<div>
<div>
{count} * 2 = {doubled}
</div>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
</div>
);
}
```
### `useStores`
```ts
import { createStore } from '/runic';
import { useStores } from '/runic-react';
import deepEqual from 'fast-deep-equal';
type User = {
id: number;
};
const userStore = createStore<User>({
id: 1,
});
type Todo = { userId: number; id: number; text: string; done: boolean };
type TodoList = {
todos: Array<Todo>;
};
const todoListStore = createStore<TodoList>({
todos: [
{ userId: 1, id: 1, text: 'First task', done: false },
{ userId: 2, id: 2, text: 'Second task', done: true },
{ userId: 1, id: 3, text: 'Third task', done: false },
],
});
const UserTodos = () => {
const userTodos = useStores<IncompleteTodos>(
// Listen for changes to any store that is passed in.
[userStore, todoListStore],
([user, todoList]) => {
return todoList.todos.filter((todo) => todo.userId === user.id);
},
// Gives you control over whether to rerender after the selector runs.
deepEqual,
);
};
```