More docs for dataverse
This commit is contained in:
parent
327b859ed4
commit
c8430050a8
15 changed files with 2923 additions and 67 deletions
|
@ -1,6 +1,8 @@
|
|||
# @theatre/react
|
||||
|
||||
Utilities for using [Theatre.js](https://www.theatrejs.com) or [Dataverse](https://github.com/theatre-js/theatre/tree/main/packages/dataverse) with React.
|
||||
Utilities for using [Theatre.js](https://www.theatrejs.com) or
|
||||
[Dataverse](https://github.com/theatre-js/theatre/tree/main/packages/dataverse)
|
||||
with React.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
@ -42,7 +44,9 @@ Usage with Theatre.js pointers:
|
|||
import {useVal} from '@theatre/react'
|
||||
import {getProject} from '@theatre/core'
|
||||
|
||||
const obj = getProject('my project').sheet('my sheet').object('my object', {foo: 'default value of props.foo'})
|
||||
const obj = getProject('my project')
|
||||
.sheet('my sheet')
|
||||
.object('my object', {foo: 'default value of props.foo'})
|
||||
|
||||
function Component() {
|
||||
const value = useVal(obj.props.foo)
|
||||
|
@ -50,11 +54,15 @@ function Component() {
|
|||
}
|
||||
```
|
||||
|
||||
_Note that `useVal()` is a React hook, so it can only be used inside a React component's render function. `val()` on the other hand, can be used either inside a `prism` (which would be reactive) or anywhere where reactive values are not needed._
|
||||
_Note that `useVal()` is a React hook, so it can only be used inside a React
|
||||
component's render function. `val()` on the other hand, can be used either
|
||||
inside a `prism` (which would be reactive) or anywhere where reactive values are
|
||||
not needed._
|
||||
|
||||
### `usePrism(fn, deps)`
|
||||
|
||||
Creates a prism out of `fn` and subscribes the element to the value of the created prism.
|
||||
Creates a prism out of `fn` and subscribes the element to the value of the
|
||||
created prism.
|
||||
|
||||
```tsx
|
||||
import {Atom, val, prism} from '@theatre/dataverse'
|
||||
|
@ -63,18 +71,74 @@ import {usePrism} from '@theatre/react'
|
|||
const state = new Atom({a: 1, b: 1})
|
||||
|
||||
function Component(props: {which: 'a' | 'b'}) {
|
||||
const value = usePrism(() => {
|
||||
prism.isPrism() // true
|
||||
// note that this function is running inside a prism, so all of prism's
|
||||
// hooks (prism.memo(), prism.effect(), etc) are available
|
||||
const num = val(props.which === 'a' ? state.pointer.a : state.pointer.b)
|
||||
return doExpensiveComputation(num)
|
||||
},
|
||||
// since our prism reads `props.which`, we should include it in the deps array
|
||||
[props.which]
|
||||
const value = usePrism(
|
||||
() => {
|
||||
prism.isPrism() // true
|
||||
// note that this function is running inside a prism, so all of prism's
|
||||
// hooks (prism.memo(), prism.effect(), etc) are available
|
||||
const num = val(props.which === 'a' ? state.pointer.a : state.pointer.b)
|
||||
return doExpensiveComputation(num)
|
||||
},
|
||||
// since our prism reads `props.which`, we should include it in the deps array
|
||||
[props.which],
|
||||
)
|
||||
return <div>{value}</div>
|
||||
}
|
||||
```
|
||||
|
||||
> Note that just like `useMemo(..., deps)`, it's necessary to provide a `deps` array to `usePrism()`.
|
||||
> Note that just like `useMemo(..., deps)`, it's necessary to provide a `deps`
|
||||
> array to `usePrism()`.
|
||||
|
||||
### `usePrismInstance(prismInstance)`
|
||||
|
||||
Subscribes the element to the value of the given prism instance.
|
||||
|
||||
```tsx
|
||||
import {Atom, val, prism} from '@theatre/dataverse'
|
||||
import {usePrismInstance} from '@theatre/react'
|
||||
|
||||
const state = new Atom({a: 1, b: 1})
|
||||
|
||||
const p = prism(() => {
|
||||
return val(state.pointer.a) + val(state.pointer.b)
|
||||
})
|
||||
|
||||
function Component() {
|
||||
const value = usePrismInstance(p)
|
||||
return <div>{value}</div>
|
||||
}
|
||||
```
|
||||
|
||||
### `useAtom(initialValue)`
|
||||
|
||||
/\*\* Creates a new Atom, similar to useState(), but the component won't
|
||||
re-render if the value of the atom changes.
|
||||
|
||||
```tsx
|
||||
import {useAtom, useVal} from '@theatre/react'
|
||||
import {useEffect} from 'react'
|
||||
|
||||
function MyComponent() {
|
||||
const atom = useAtom({count: 0, ready: false})
|
||||
|
||||
const onClick = () =>
|
||||
atom.setByPointer(
|
||||
(p) => p.count,
|
||||
(count) => count + 1,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
atom.setByPointer((p) => p.ready, true)
|
||||
}, 1000)
|
||||
}, [])
|
||||
|
||||
const ready = useVal(atom.pointer.ready)
|
||||
if (!ready) return <div>Loading...</div>
|
||||
return <button onClick={onClick}>Click me</button>
|
||||
}
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- Learn more about [Dataverse](../dataverse/README.md)
|
||||
|
|
|
@ -5,18 +5,10 @@
|
|||
*/
|
||||
|
||||
import type {Prism} from '@theatre/dataverse'
|
||||
import {Atom} from '@theatre/dataverse'
|
||||
import {prism, val} from '@theatre/dataverse'
|
||||
import {prism, val, Atom} from '@theatre/dataverse'
|
||||
import {findIndex} from 'lodash-es'
|
||||
import queueMicrotask from 'queue-microtask'
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {useCallback, useLayoutEffect, useRef, useState} from 'react'
|
||||
import {unstable_batchedUpdates} from 'react-dom'
|
||||
|
||||
type $IntentionalAny = any
|
||||
|
@ -374,38 +366,44 @@ export function usePrismInstance<T>(der: Prism<T>, debugLabel?: string): T {
|
|||
}
|
||||
|
||||
/**
|
||||
* This makes sure the prism prism remains hot as long as the
|
||||
* component calling the hook is alive, but it does not
|
||||
* return the value of the prism, and it does not
|
||||
* re-render the component if the value of the prism changes.
|
||||
* Creates a new Atom, similar to useState(), but the component
|
||||
* won't re-render if the value of the atom changes.
|
||||
*
|
||||
* Use this hook if you plan to read a prism in a
|
||||
* useEffect() call, without the prism causing your
|
||||
* element to re-render.
|
||||
* @param initialState - Initial state
|
||||
* @returns The Atom
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* Usage
|
||||
* ```tsx
|
||||
* import {useAtom, useVal} from '@theatre/react'
|
||||
* import {useEffect} from 'react'
|
||||
*
|
||||
* function MyComponent() {
|
||||
* const atom = useAtom({count: 0, ready: false})
|
||||
*
|
||||
* const onClick = () =>
|
||||
* atom.setByPointer(
|
||||
* (p) => p.count,
|
||||
* (count) => count + 1,
|
||||
* )
|
||||
*
|
||||
* useEffect(() => {
|
||||
* setTimeout(() => {
|
||||
* atom.setByPointer((p) => p.ready, true)
|
||||
* }, 1000)
|
||||
* }, [])
|
||||
*
|
||||
* const ready = useVal(atom.pointer.ready)
|
||||
* if (!ready) return <div>Loading...</div>
|
||||
* return <button onClick={onClick}>Click me</button>
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function usePrismWithoutReRender<T>(
|
||||
fn: () => T,
|
||||
deps: unknown[],
|
||||
): Prism<T> {
|
||||
const pr = useMemo(() => prism(fn), deps)
|
||||
|
||||
return usePrismInstanceWithoutReRender(pr)
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes sure the prism remains hot as long as the
|
||||
* component calling the hook is alive, but it does not
|
||||
* return the value of the prism, and it does not
|
||||
* re-render the component if the value of the prism changes.
|
||||
*/
|
||||
export function usePrismInstanceWithoutReRender<T>(der: Prism<T>): Prism<T> {
|
||||
useEffect(() => {
|
||||
const untap = der.keepHot()
|
||||
|
||||
return () => {
|
||||
untap()
|
||||
}
|
||||
}, [der])
|
||||
|
||||
return der
|
||||
export function useAtom<T>(initialState: T): Atom<T> {
|
||||
const ref = useRef<Atom<T>>(undefined as $IntentionalAny)
|
||||
if (!ref.current) {
|
||||
ref.current = new Atom(initialState)
|
||||
}
|
||||
return ref.current
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue