
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
@tldraw/state
Advanced tools
@tldraw/state
is a powerful and lightweight TypeScript library for managing reactive state using signals. It provides fine-grained reactive primitives that automatically track dependencies and efficiently update only what needs to change.
@tldraw/state
powers the reactive system at the heart of tldraw, handling everything from canvas updates to collaborative state synchronization. It's designed to work seamlessly with @tldraw/store and has optional React bindings.
Perfect for building reactive UIs, real-time collaborative apps, and complex state machines where performance and predictability matter.
npm install @tldraw/state
import { atom, computed, react } from '@tldraw/state'
// Create reactive state
const name = atom('name', 'World')
const count = atom('count', 0)
// Derive values automatically
const greeting = computed('greeting', () => {
return `Hello, ${name.get()}! Count: ${count.get()}`
})
// React to changes
react('logger', () => {
console.log(greeting.get())
})
// Logs: "Hello, World! Count: 0"
// Update state - reactions run automatically
name.set('tldraw')
// Logs: "Hello, tldraw! Count: 0"
count.set(42)
// Logs: "Hello, tldraw! Count: 42"
Atoms hold raw values and are the foundation of your reactive state:
import { atom } from '@tldraw/state'
// Create atoms with initial values
const user = atom('user', { name: 'Alice', age: 30 })
const theme = atom('theme', 'light')
// Read values
console.log(user.get().name) // 'Alice'
// Update values
user.update((current) => ({ ...current, age: 31 }))
theme.set('dark')
Computed signals derive their values from other signals and update automatically:
import { computed } from '@tldraw/state'
const firstName = atom('firstName', 'John')
const lastName = atom('lastName', 'Doe')
const fullName = computed('fullName', () => {
return `${firstName.get()} ${lastName.get()}`
})
console.log(fullName.get()) // "John Doe"
firstName.set('Jane')
console.log(fullName.get()) // "Jane Doe" - automatically updated!
Reactions run side effects when their dependencies change:
import { react } from '@tldraw/state'
const selectedId = atom('selectedId', null)
// Update UI when selection changes
const stop = react('update-selection-ui', () => {
const id = selectedId.get()
document.getElementById('selected').textContent = id || 'None'
})
selectedId.set('shape-123')
// UI automatically updates
// Clean up when no longer needed
stop()
Batch multiple updates to prevent intermediate reactions:
import { transact } from '@tldraw/state'
const x = atom('x', 0)
const y = atom('y', 0)
const position = computed('position', () => `(${x.get()}, ${y.get()})`)
react('log-position', () => console.log(position.get()))
// Logs: "(0, 0)"
transact(() => {
x.set(10)
y.set(20)
// Reaction runs only once after transaction
})
// Logs: "(10, 20)"
Track changes over time for undo/redo functionality:
const canvas = atom(
'canvas',
{ shapes: [] },
{
historyLength: 100,
computeDiff: (prev, next) => ({ prev, next }),
}
)
// Make changes...
canvas.update((state) => ({ shapes: [...state.shapes, newShape] }))
// Get diffs since a point in time
const startTime = getGlobalEpoch()
// ... make more changes ...
const diffs = canvas.getDiffSince(startTime)
Use unsafe__withoutCapture
to read values without creating dependencies:
const expensiveComputed = computed('expensive', () => {
const important = importantValue.get()
// Read this without making it a dependency
const metadata = unsafe__withoutCapture(() => metadataAtom.get())
return computeExpensiveValue(important, metadata)
})
Use whyAmIRunning()
to understand what triggered an update:
react('debug-reaction', () => {
whyAmIRunning() // Logs dependency tree to console
// Your reaction code...
})
// In a tldraw application
const editor = useEditor()
// Create reactive state that works with tldraw
const selectedShapes = computed('selectedShapes', () => {
return editor.getSelectedShapeIds().map((id) => editor.getShape(id))
})
// React to selection changes
react('update-property-panel', () => {
const shapes = selectedShapes.get()
updatePropertyPanel(shapes)
})
Install the React bindings:
npm install @tldraw/state-react
import { useAtom, useComputed } from '@tldraw/state-react'
function Counter() {
const [count, setCount] = useAtom(countAtom)
const doubled = useComputed(() => count * 2, [count])
return (
<div>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
For complete API documentation, see DOCS.md.
atom(name, initialValue, options?)
- Create a reactive state containercomputed(name, computeFn, options?)
- Create a derived valuereact(name, effectFn, options?)
- Create a side effecttransact(fn)
- Batch state updates@computed
- Decorator for computed class propertiesreactor(name, effectFn)
- Create a controllable reactionunsafe__withoutCapture(fn)
- Read state without creating dependencieswhyAmIRunning()
- Debug what triggered an updategetComputedInstance(obj, prop)
- Get underlying computed instancegetGlobalEpoch()
- Get current time for history trackingLooking for more examples? Check out:
Please see our contributing guide. Found a bug? Please submit an issue.
This project is licensed under the MIT License found here. The tldraw SDK is provided under the tldraw license.
Copyright (c) 2024-present tldraw Inc. The tldraw name and logo are trademarks of tldraw. Please see our trademark guidelines for info on acceptable usage.
Find us on Twitter/X at @tldraw. You can contact us by email at hello@tldraw.com.
Have questions, comments or feedback? Join our discord. For the latest news and release notes, visit tldraw.dev.
FAQs
tldraw infinite canvas SDK (state).
The npm package @tldraw/state receives a total of 52,962 weekly downloads. As such, @tldraw/state popularity was classified as popular.
We found that @tldraw/state demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.