cells
所属分类:工具库
开发工具:TypeScript
文件大小:0KB
下载次数:0
上传日期:2024-01-24 06:12:41
上 传 者:
sh-1993
说明: 函数式和 React编程库
(A Functional & Reactive Programming library)
文件列表:
.vscode/
assets/
src/
LICENSE
package-lock.json
package.json
tsconfig.build.json
tsconfig.json
vite.config.js
vitest.config.mjs
# Cells: A Functional & Reactive Programming library
`cells` is a Functional & Reactive Programming (FRP) library inspired by
spreadsheets. This programming paradigm simplifies handling complex, dynamic
data flows. It is particularly useful in scenarios with asynchronous data
sources, such as user interfaces or real-time data feeds.
![cells are either values or functions](https://github.com/okcontract/cells/blob/master/./assets/cells.svg)
`cells` focuses on automation as it transparently manages:
- `async` calls
- undefined values
- errors
- pointers
Although it is a fully independent library, `cells` can be a powerful drop-in
replacement for Svelte stores. The build artifacts are currently at 17.32 kB
(5.43 kB gzipped).
## Walkthrough
```typescript
import { Sheet } from "@okcontract/cells";
// create a new Sheet, typically one per application
const sheet = new Sheet();
// that's a cell
const cellA = sheet.new(1);
// no need to wait for anything, values and computations will
// be called automatically when they're ready
const cellB = sheet.new(getValueAfterDelay(2, 100));
// that's a _mapped_ cell, that is recomputed automatically when
// either dependent cells are updated
const sum = sheet.map([cellA, cellB], (a, b) => a + b);
// you can map a single cell directly
// and feel free to define mapped cells before their values are available
const prod = cellB.map((v) => 2 * v);
// we await _only_ when we need results
expect(await prod.get()).toBe(4);
// you can update _value_ cells directly (no await)
cellA.set(3);
expect(await sum.get()).toBe(5);
// map computations can be async too
const ok = someCell.map(async (v) => {
const errors = await validate(v);
return errors.length === 0;
});
```
Note that:
- `.get()` never returns `undefined` and `cells` semantics waits until cell
values are defined. If you need to immediately return a value, use `null`
instead.
- At any time, the actual cell value is accessible through `cell.value`
(possibly undefined) but it's advisable to avoid relying on a value that could
be updated at any moment.
## Subscriptions
You can define subscribers functions to be called whenever a cell value change.
```ts
const cellA = sheet.new(1);
// create subscriptions on any cell
const unsubscribe = cellA.subscribe((v) => {
console.log({ v });
});
// later call `unsubscribe` to cancel the subscription
unsubscribe();
```
When using `cells` in Svelte files, you can use the `$cell` sugar to subscribe
to a cell value for display. Note that there is a initial `undefined` value when
using that sugar as the reactive subscription are initially output by the Svelte
compiler as `let $cell;`.
Unlike Svelte, subscriptions are called in transactional batches, i.e. `cells`
wait until all updates are propagated in the `Sheet` to dispatch notifications
_once_ to subscribers. This prevents stuttering.
## Memory management and proxies
Cells are not garbage collected automatically, since the best practice is to
keep a long-running `Sheet` for each application.
To delete a cell, use:
```ts
sheet.delete(cell);
```
To simplify these operations, you can define a sub-graph of cells in a `Proxy`
that can be deleted at once.
```ts
import { SheetProxy } from "@okcontract/cells";
// create a proxy (for instance in a Svelte component)
const proxy = new SheetProxy(sheet);
// use the proxy to create new cells...
const cell = proxy.new(1);
// ...and mapped cells
const mappedCell = proxy.map([...cells], (...args)=>{...})
// delete the proxy when you're done
proxy.destroy();
```
There are added benefits of proxies, including a single call to wait for all
cells in a `Proxy` to be computed.
```ts
await proxy.working.wait();
```
## Pointers
Sometimes, you will need to return cells inside `.map` compute functions.
`cells` manages this automatically with pointers.
```ts
const cellA = proxy.new(...);
const cellB = proxy.new(...);
// pointerCell will either be cellA or cellB
const pointerCell = proxy.map([cellA, cellB], (a, b) =>
condition ? cellA : cellB
);
// breathe normally
await pointerCell.get();
pointerCell.map(...);
```
## Cell updates
It's easy to update cells depending on their previous value:
```ts
const counter = proxy.new(0);
// ...
counter.update((prev) => prev + 1);
```
Note that `update` functions should return new arrays and objects, for instance
using spread operators `[...prev, new]` and `{...prev, field: new}`.
If you need more complex imperative updates, we suggest you to use `immer`:
```typescript
import { produce } from "immer";
const patch = (prev) => {
// complex updates...
};
cell.update((prev) => produce(prev, patch));
```
# Design & Philosophy
The design and philosophy of cells are influenced by frameworks like `RxJS`,
`MobX`, and `Recoil`, with increased automation. Our focus is to streamline the
developer experience, reduce the boilerplate and complexity often encountered in
state management and reactive programming.
# About
`cells` is built at [OKcontract](https://github.com/okcontract/cells/blob/master/https://okcontract.com) and is released under
the MIT license.
We aim for ease of use and correction. Chasing down any bug is our top priority.
A non-goal for now is high-performance: `cells` is slower than any direct
implementation and should not be used for computationally intensive tasks.
Contributors are welcome, feel free to submit PRs directly for small changes.
You can also reach out in our [Discord](https://github.com/okcontract/cells/blob/master/https://discord.gg/Cun5aF7k) or contact
us on [Twitter](https://github.com/okcontract/cells/blob/master/https://x.com/okcontract) in advance for larger contributions.
This work is supported in part by a RFG grant from
[Optimism](https://github.com/okcontract/cells/blob/master/https://optimism.io).
近期下载者:
相关文件:
收藏者: