State/store example (#4147)
An example of how to subscribe to values in the store and run side effects using reactors. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` ### Test plan 1. Create a shape... 2. - [ ] Unit tests - [ ] End to end tests ### Release notes - Added an example that shows how to use track, useValue and useReactor --------- Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
This commit is contained in:
parent
1c35ed27f9
commit
85f36639ff
2 changed files with 100 additions and 0 deletions
12
apps/examples/src/examples/state-store/README.md
Normal file
12
apps/examples/src/examples/state-store/README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: State and store
|
||||
component: ./StateStoreExample.tsx
|
||||
category: basic
|
||||
priority: 3
|
||||
keywords: [signia, state, store, side, effects, subscribe, track]
|
||||
---
|
||||
|
||||
Tldraw uses signals to manage its state and store. You can subscribe to
|
||||
values in the store and run side effects when they change.
|
||||
|
||||
---
|
88
apps/examples/src/examples/state-store/StateStoreExample.tsx
Normal file
88
apps/examples/src/examples/state-store/StateStoreExample.tsx
Normal file
|
@ -0,0 +1,88 @@
|
|||
import { TLComponents, Tldraw, track, useEditor, useReactor, useValue } from 'tldraw'
|
||||
import 'tldraw/tldraw.css'
|
||||
|
||||
// [1]
|
||||
const InfoPanel = track(() => {
|
||||
const editor = useEditor()
|
||||
const tool = editor.getCurrentToolId()
|
||||
const zoom = editor.getZoomLevel().toFixed(2)
|
||||
useReactor(
|
||||
'change title',
|
||||
() => {
|
||||
const shapes = editor.getCurrentPageShapes()
|
||||
document.title = `shapes: ${shapes.length}`
|
||||
},
|
||||
[editor]
|
||||
)
|
||||
return (
|
||||
<div style={{ pointerEvents: 'all', backgroundColor: 'thistle', fontSize: 14, padding: 8 }}>
|
||||
<div>tool: {tool}</div>
|
||||
<div>zoom: {zoom}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
// [2]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function AlternativeInfoPanel() {
|
||||
const editor = useEditor()
|
||||
const tool = useValue(
|
||||
'current tool',
|
||||
() => {
|
||||
if (!editor) throw new Error('No editor')
|
||||
return `Current Tool: ${editor.getCurrentToolId()}`
|
||||
},
|
||||
[editor]
|
||||
)
|
||||
const zoom = useValue(
|
||||
'zoom',
|
||||
() => {
|
||||
if (!editor) throw new Error('No editor')
|
||||
return `Zoom Level: ${editor.getZoomLevel().toFixed(2)}`
|
||||
},
|
||||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<div style={{ pointerEvents: 'all', backgroundColor: 'thistle', fontSize: 14, padding: 8 }}>
|
||||
<div>{tool}</div>
|
||||
<div>{zoom}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const components: TLComponents = {
|
||||
SharePanel: InfoPanel,
|
||||
}
|
||||
|
||||
export default function StateStoreExample() {
|
||||
return (
|
||||
<div className="tldraw__editor">
|
||||
<Tldraw components={components} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Tldraw uses signals to manage its state and store. You can subscribe to values in the store
|
||||
and run side effects when they change.
|
||||
|
||||
[1]
|
||||
Our InfoPanel component will display above the style panel. We want it to show the current
|
||||
selected tool and zoom level of the editor. In order to make sure it displays up-to-date
|
||||
information, we can wrap the component in the track function. This will track any signals
|
||||
used in the component and re-render it when they change.
|
||||
|
||||
We also use the useReactor hook to update the document title with the number of shapes. This
|
||||
side effect will run whenever the shapes on the page change. We pass the editor as a
|
||||
dependency to the useReactor hook so it will always have the latest editor instance.
|
||||
useQuickReactor runs immediately, whereas useReactor runs on the next animation frame.
|
||||
|
||||
Check out the Fog of War example to see useReactor in action.
|
||||
|
||||
[2]
|
||||
We can also use the useValue hook to subscribe to a value in the store. You can pass it a
|
||||
value or a function. Functions will be memoized and only re-run when the dependencies change.
|
||||
|
||||
*/
|
Loading…
Reference in a new issue