mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Update docs
This commit is contained in:
parent
94add5d452
commit
a3cc2dfbda
30 changed files with 850 additions and 770 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Animation API
|
||||
# Animation
|
||||
|
||||
## spring()
|
||||
## spring() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Returns a new source with a value always moving torwards the input source value.
|
||||
|
||||
|
|
@ -18,8 +18,7 @@ Returns a new source with a value always moving torwards the input source value.
|
|||
|
||||
- **Details**
|
||||
|
||||
An effect is created to update the new source every frame based on the input
|
||||
source value.
|
||||
Creates a reactive scope internally to detect source updates.
|
||||
|
||||
The movement is physically simulated according to a
|
||||
[spring](https://en.wikipedia.org/wiki/Simple_harmonic_motion).
|
||||
|
|
@ -39,3 +38,7 @@ Returns a new source with a value always moving torwards the input source value.
|
|||
You can change when the solver runs by calling `vide.step(dt)`, which will
|
||||
advance the simulation time by `dt` seconds and automatically stop the
|
||||
solver running in heartbeat.
|
||||
|
||||
::: warning
|
||||
Large periods or damping ratios can break the spring.
|
||||
:::
|
||||
|
|
|
|||
|
|
@ -1,39 +1,4 @@
|
|||
# Element Creation API
|
||||
|
||||
<br/>
|
||||
|
||||
## mount()
|
||||
|
||||
Runs a function in a new stable scope and optionally applies its result to a
|
||||
target instance.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function mount<T>(component: () -> T, target: Instance?): () -> ()
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
The result of the function is applied to a target in the same way
|
||||
properties are using `create()`.
|
||||
|
||||
The function is ran in a new stable scope, just like
|
||||
[root()](reactivity-core.md#root).
|
||||
|
||||
Returns a function that when called will destroy the stable scope.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local function App()
|
||||
return create "ScreenGui" {
|
||||
create "TextLabel" { Text = "Vide" }
|
||||
}
|
||||
end
|
||||
|
||||
mount(App, game.StarterGui)
|
||||
```
|
||||
# Element Creation
|
||||
|
||||
## create()
|
||||
|
||||
|
|
@ -45,7 +10,7 @@ Creates a new UI element, applying any given properties.
|
|||
function create(class: string): (Properties) -> Instance
|
||||
function create(instance: Instance): (Properties) -> Instance
|
||||
|
||||
type Properties = Map<string|number, any>
|
||||
type Properties = Map<string|number, unknown>
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
|
@ -77,42 +42,22 @@ Creates a new UI element, applying any given properties.
|
|||
Basic element creation.
|
||||
|
||||
```luau
|
||||
local frame = create "Frame" {
|
||||
Name = "NewFrame",
|
||||
Position = UDim2.fromScale(1, 0)
|
||||
local frame = create "TextButton" {
|
||||
Name = "Button",
|
||||
Size = UDim2.fromOffset(200, 160),
|
||||
|
||||
Activated = function()
|
||||
print "clicked"
|
||||
end,
|
||||
|
||||
create "UICorner" {}
|
||||
}
|
||||
```
|
||||
|
||||
A component using property nesting.
|
||||
|
||||
```luau
|
||||
type Layout = {
|
||||
Layout = {
|
||||
Position: UDim2?,
|
||||
Size: UDim2?,
|
||||
AnchorPoint: Vector2?
|
||||
}
|
||||
}
|
||||
|
||||
type Children = {
|
||||
Children = Array<Instance>
|
||||
}
|
||||
|
||||
function Background(props: Layout & Children & {
|
||||
Color: Color3
|
||||
})
|
||||
return create "Frame" {
|
||||
BackgroundColor3 = props.Color,
|
||||
props.Layout,
|
||||
props.Children
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
## action()
|
||||
|
||||
Creates a callback that can be passed to `create()` to invoke custom actions on
|
||||
instances.
|
||||
Creates a special object that can be passed to `create()` to invoke custom
|
||||
actions on instances.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -122,27 +67,27 @@ instances.
|
|||
|
||||
- **Details**
|
||||
|
||||
When passed to `create()`, the given callback is called with the instance
|
||||
being created as the only argument. Actions take precedence over property
|
||||
and child assignments.
|
||||
When passed to `create()`, the function is called with the instance being
|
||||
created as the only argument. Actions take precedence over property and
|
||||
child assignments.
|
||||
|
||||
A priority can be optionally specified to ensure certain actions run after
|
||||
other actions. Higher priority numbers are ran after lower priority numbers.
|
||||
other actions. Lower priority values are ran first.
|
||||
|
||||
- **Example**
|
||||
|
||||
An action to listen to changed properties:
|
||||
|
||||
```luau
|
||||
local function changed(property: string, callback: (new) -> ())
|
||||
local function changed(property: string, fn: (new) -> ())
|
||||
return action(function(instance)
|
||||
local con - instance:GetPropertyChangedSignal(property):Connect(function()
|
||||
callback(instance[property])
|
||||
local cn = instance:GetPropertyChangedSignal(property):Connect(function()
|
||||
fn(instance[property])
|
||||
end)
|
||||
|
||||
-- disconnect on reactive scope destruction to allow gc of instance
|
||||
-- disconnect on scope destruction to allow gc of instance
|
||||
cleanup(function()
|
||||
con:Disconnect()
|
||||
cn:Disconnect()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
@ -150,7 +95,7 @@ instances.
|
|||
local output = source ""
|
||||
|
||||
create "TextBox" {
|
||||
-- will update the `output` source anytime the text property is changed
|
||||
-- will update the output source anytime the text property is changed
|
||||
changed("Text", output)
|
||||
}
|
||||
```
|
||||
|
|
@ -162,15 +107,46 @@ A wrapper for `action()` to listen for property changes.
|
|||
- **Type**
|
||||
|
||||
```luau
|
||||
function changed(property: string, callback: (...unknown) -> ()): Action
|
||||
function changed(property: string, fn: (unknown) -> ()): Action
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Will run the given callback any time the property is changed, as well as
|
||||
when the action is initially run.
|
||||
Will run the given function immediately and whenever the property updates.
|
||||
|
||||
The changed connection is disconnected when the scope the action is ran in
|
||||
is destroyed.
|
||||
The function is called with the updated property value.
|
||||
|
||||
Runs with an action priority of 1.
|
||||
|
||||
## mount() <Badge type="info" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">STABLE</a></Badge>
|
||||
|
||||
Runs a function in a new stable scope and optionally applies its result to a
|
||||
target instance.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function mount<T>(component: () -> T, target: Instance?): () -> ()
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
This is a utility for `root()` when parenting a component to an existing
|
||||
instance.
|
||||
|
||||
The result of the function is applied to a target in the same way
|
||||
properties are using `create()`.
|
||||
|
||||
Returns a function that when called will destroy the stable scope.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local function App()
|
||||
return create "ScreenGui" {
|
||||
create "TextLabel" { Text = "Vide" }
|
||||
}
|
||||
end
|
||||
|
||||
local destroy = mount(App, game.StarterGui)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,32 +1,40 @@
|
|||
# Reactivity API: Core
|
||||
# Reactivity: Core
|
||||
|
||||
<br/>
|
||||
## Scopes
|
||||
|
||||
Vide code can run in one of two scopes: <Badge type="info" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">STABLE</a></Badge> or <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>.
|
||||
|
||||
- Reactive scopes rerun if a source read within updates.
|
||||
- Stable scopes never rerun.
|
||||
- Reactive scopes cannot be created directly within another reactive scope.
|
||||
- When a scope is destroyed, all scopes created within are also destroyed.
|
||||
|
||||
Different functions in Vide's API will run code in different scopes.
|
||||
|
||||
:::warning
|
||||
Yielding is not allowed in any stable or reactive scope. Strict mode will check
|
||||
for this.
|
||||
:::
|
||||
|
||||
## root()
|
||||
## root() <Badge type="info" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">STABLE</a></Badge>
|
||||
|
||||
Creates and runs a function in a new stable scope.
|
||||
Runs a function in a new stable scope.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function root<T...>(fn: (() -> ()) -> T...): (() -> (), T...)
|
||||
function root<T...>(fn: (Destructor) -> T...): (Destructor, T...)
|
||||
|
||||
type Destructor = () -> ()
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Returns a function to destroy the root scope. Also passes this function as
|
||||
the first argument into its callback.
|
||||
|
||||
All values returned by the callback are also returned following the destructor.
|
||||
Returns a destructor and any values returned by the callback.
|
||||
|
||||
## source()
|
||||
|
||||
Creates a new source with the given value.
|
||||
Creates a new source.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -40,71 +48,64 @@ Creates a new source with the given value.
|
|||
|
||||
- **Details**
|
||||
|
||||
Calling the returned source with no argument will return its stored value,
|
||||
calling with an argument will set a new value.
|
||||
Call the returned source with no argument to read its value.
|
||||
Call the returned source with an argument to set its value.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local count = source(0)
|
||||
|
||||
count() -- 0
|
||||
|
||||
count(count() + 1) -- 1
|
||||
print(count())-- 0
|
||||
count(count() + 1)
|
||||
print(count()) -- 1
|
||||
```
|
||||
|
||||
## effect()
|
||||
## effect() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Runs a side-effect in a new reactive scope on source update.
|
||||
Runs a function in a new reactive scope.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function effect(callback: () -> ())
|
||||
function effect(fn: () -> ())
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Any time a source referenced in the callback is updated, the callback will
|
||||
be reran.
|
||||
|
||||
The callback is ran once immediately.
|
||||
The function is ran once immediately.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local num = source(1)
|
||||
local count = source(1)
|
||||
|
||||
effect(function()
|
||||
print(num())
|
||||
print(count())
|
||||
end)
|
||||
|
||||
-- prints 1
|
||||
|
||||
num(num() + 1)
|
||||
count(2)
|
||||
|
||||
-- prints 2
|
||||
```
|
||||
|
||||
## derive()
|
||||
## derive() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Derives a new source in a new reactive scope from existing sources.
|
||||
Runs a function in a new reactive scope to compute a value for new source.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function derive<T>(source: () -> T): () -> T
|
||||
function derive<T>(fn: () -> T): () -> T
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
The derived source will have its value recalculated when any source source
|
||||
it derives from is updated.
|
||||
Anytime the reactive scope reruns, the output source value is set to what is
|
||||
returned.
|
||||
|
||||
Anytime its value is recalculated it is also cached, subsequent calls will
|
||||
retun this cached value until it recalculates again.
|
||||
|
||||
The callback is ran once immediately.
|
||||
The function is ran once immediately.
|
||||
|
||||
- **Example**
|
||||
|
||||
|
|
@ -112,11 +113,43 @@ Derives a new source in a new reactive scope from existing sources.
|
|||
local count = source(0)
|
||||
local text = derive(function() return `count: {count()}` end)
|
||||
|
||||
text() -- "count: 0"
|
||||
print(text()) -- "count: 0"
|
||||
|
||||
count(1)
|
||||
|
||||
text() -- "count: 1"
|
||||
print(text()) -- "count: 1"
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
A `derive()` should be used instead of a pure function when you expect it to
|
||||
be read multiple times between updates, because `derive()` will cache the
|
||||
result to prevent recomputing it on every read.
|
||||
|
||||
::: code-group
|
||||
|
||||
```luau [Pure Function]
|
||||
local count = source(0)
|
||||
|
||||
local text = function()
|
||||
print "ran"
|
||||
return `count: {count()}`
|
||||
end
|
||||
|
||||
count(1)
|
||||
print(text()) -- prints "ran" followed by "count: 1"
|
||||
print(text()) -- prints "ran" followed by "count: 1"
|
||||
```
|
||||
|
||||
```luau [Derived Source]
|
||||
local count = source(0)
|
||||
|
||||
local text = derive(function() -- [!code highlight]
|
||||
print "ran"
|
||||
return `count: {count()}`
|
||||
end) -- [!code highlight]
|
||||
|
||||
count(1) -- prints "ran"
|
||||
print(text()) -- prints "count: 1"
|
||||
print(text()) -- prints "count: 1"
|
||||
```
|
||||
|
||||
:::
|
||||
|
|
|
|||
212
docs/api/reactivity-dynamic.md
Normal file
212
docs/api/reactivity-dynamic.md
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
# Reactivity: Dynamic Scoping
|
||||
|
||||
Dynamic scoping is the act of creating and destroying new scopes in response to
|
||||
source updates. Vide provides functions for some common use-cases to do this.
|
||||
|
||||
## show() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Shows a component if the source is truthy. Optionally shows a fallback component
|
||||
if the source is falsey.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function show<T>(source: () -> unknown, component: () -> T): () -> T?
|
||||
function show<T, U>(source: () -> unknown, component: () -> T, fallback: () -> U): () -> T | U
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Creates a reactive scope internally to detect source updates.
|
||||
|
||||
The component is run in a stable scope when truthy, otherwise the stable
|
||||
scope is destroyed.
|
||||
|
||||
Returns a source holding an instance of the currently shown component or
|
||||
`nil` if no component is currently shown.
|
||||
|
||||
## switch() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Shows one of a set of components depending on a source and a mapping table.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function switch<K, V>(source: () -> K): (map: Map<K, () -> V>) () -> V?
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Creates a reactive scope internally to detect source updates.
|
||||
|
||||
When the source updates, its value is inputted into a map to get a component
|
||||
constructor. This component is then run in a stable scope. The previous
|
||||
stable scope is destroyed.
|
||||
|
||||
Returns a source holding an instance of the currently shown component or
|
||||
`nil` if no component is currently shown.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local logged = source(false)
|
||||
|
||||
local button = switch(logged) {
|
||||
[true] = function()
|
||||
return Button { Text = "Log out", Toggle = logged }
|
||||
end,
|
||||
|
||||
[false] = function()
|
||||
return Button { Text = "Log in", Toggle = logged }
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
## indexes() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Shows a component for each index in a table.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function indexes<KI, VI, VO>(
|
||||
source: () -> Map<KI, VI>,
|
||||
transform: (value: () -> VI, index: KI) -> VO
|
||||
): Array<VO>
|
||||
|
||||
- **Details**
|
||||
|
||||
Creates a reactive scope internally to detect source updates.
|
||||
|
||||
When the source table updates, a component is generated for each index in
|
||||
the table.
|
||||
|
||||
- For any added index, the `transform` function is run in a new stable
|
||||
scope to produce an instance that is cached.
|
||||
- For any removed index, the stable scope for that index is destroyed.
|
||||
|
||||
The `transform` function is called with:
|
||||
|
||||
1. A *source containing the index's value*.
|
||||
2. The *index itself*.
|
||||
|
||||
Anytime an existing index's value changes, the `transform` function is not
|
||||
rerun, instead, that index's corresponding source is updated with the new
|
||||
value.
|
||||
|
||||
Returns a source holding an array of instances currently shown.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
type Item = {
|
||||
name: string,
|
||||
icon: number
|
||||
}
|
||||
|
||||
local items = source {} :: () -> Array<Item>
|
||||
|
||||
local displays = indexes(items, function(item, i)
|
||||
return ItemDisplay {
|
||||
Name = function()
|
||||
return i .. ": " .. item().name
|
||||
end,
|
||||
|
||||
Image = function()
|
||||
return "rbxassetid://" .. item().icon
|
||||
end,
|
||||
}
|
||||
end)
|
||||
```
|
||||
|
||||
## values() <Badge type="tip" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">REACTIVE</a></Badge>
|
||||
|
||||
Shows a component for each value in a table.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function values<KI, VI, VO>(
|
||||
source: () -> Map<KI, VI>,
|
||||
transform: (value: VI, index: () -> KI) -> VO
|
||||
): Array<VO>
|
||||
|
||||
- **Details**
|
||||
|
||||
Operates with the same idea as `indexes()`, but applied to values instead of
|
||||
indexes.
|
||||
|
||||
Creates a reactive scope internally to detect source updates.
|
||||
|
||||
When the source table updates, a component is generated for each value in
|
||||
the table.
|
||||
|
||||
- For any added value, the `transform` function is run in a new stable scope
|
||||
to produce an instance that is cached.
|
||||
- For any removed value, the stable scope for that value is destroyed.
|
||||
|
||||
The `transform` function is called with:
|
||||
|
||||
1. The *value itself*.
|
||||
2. A *source containing the value's index*.
|
||||
|
||||
Anytime an existing value's index changes, the `transform` function is not
|
||||
rerun, instead, that value's corresponding source is updated with the new
|
||||
index.
|
||||
|
||||
Returns a source holding an array of instances currently shown.
|
||||
|
||||
::: warning
|
||||
Having the same values appear multiple times in the input source table can
|
||||
cause unexpected behavior. Strict mode has checks for this.
|
||||
:::
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
type Item = {
|
||||
name: string,
|
||||
icon: number
|
||||
}
|
||||
|
||||
local items = source {} :: () -> Array<Item>
|
||||
|
||||
local displays = values(items, function(item, i)
|
||||
return ItemDisplay {
|
||||
Name = function()
|
||||
return i() .. ": " .. item.Name
|
||||
end
|
||||
|
||||
Image = "rbxassetid://" .. item.icon,
|
||||
}
|
||||
end)
|
||||
```
|
||||
|
||||
- **Extra**
|
||||
|
||||
When should you use `indexes()` and `values()`?
|
||||
|
||||
`values()` should be used when you have a fixed set of objects where the
|
||||
same objects can be re-arranged in the source table. It maps a value to a
|
||||
UI element.
|
||||
|
||||
e.g.
|
||||
- List of all players.
|
||||
- Inventory of items.
|
||||
- Chat message history.
|
||||
- Toast notifications.
|
||||
|
||||
`indexes()` should be used in other cases, especially when your source table
|
||||
has primitive values. It maps an index to a UI element.
|
||||
|
||||
e.g.
|
||||
- List of character or weapon stats.
|
||||
|
||||
In most cases, both functions will produce the same observed result.
|
||||
The main difference is performance, picking the right function to use can
|
||||
result in less property updates and less re-renders. One case to note is
|
||||
that `values()` works nicely when animating re-ordering of instances, since
|
||||
the source index can be used to animate a change in position for the UI
|
||||
element.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
# Reactivity API: Control Flow
|
||||
|
||||
<br/>
|
||||
|
||||
## show()
|
||||
|
||||
Shows one of two components depending on an input source.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function show<T>(source: () -> unknown, component: () -> T): () -> T?
|
||||
function show<T, U>(source: () -> unknown, component: () -> T, fallback: () -> U): () -> T | U
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Returns a source holding an instance of the currently shown component.
|
||||
|
||||
When the input source changes from a falsey to a truthy value, the
|
||||
component will be reran under a new stable scope. If it changes from a
|
||||
truthy to falsey value, the stable scope the component was created in will
|
||||
be destroyed, and the returned source will output `nil`, or a fallback
|
||||
component if given.
|
||||
|
||||
The fallback component is also ran under a new stable scope, and destroyed
|
||||
when the input source switches back to truthy.
|
||||
|
||||
## switch()
|
||||
|
||||
Shows one of a set of components depending on an input source and a mapping table.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function switch<K, V>(source: () -> K): (map: Map<K, () -> V>) -> V?
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Returns a source holding an instance of the currently shown component.
|
||||
|
||||
When the input source changes, the new value will be used to lookup a given
|
||||
mapping table to get a component, which will be ran under a new stable
|
||||
scope. If the input source changes, the stable scope the component was
|
||||
created in will be destroyed, and a new component created under a new
|
||||
stable scope. If no component is found for an input value, the switch will
|
||||
output `nil`.
|
||||
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local logged = source(false)
|
||||
|
||||
local button = switch(logged) {
|
||||
[true] = function()
|
||||
return Button { Text = "Log out", Toggle = logged }
|
||||
end,
|
||||
|
||||
[false] = function()
|
||||
return Button { Text = "Log in", Toggle = logged }
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
## indexes()
|
||||
|
||||
Maps each index in a table source to an object.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function indexes<KI, VI, VO>(
|
||||
source: () -> Map<KI, VI>,
|
||||
transform: (value: () -> VI, index: KI) -> VO
|
||||
): Array<VO>
|
||||
|
||||
- **Details**
|
||||
|
||||
Returns a source holding an array of instances currently shown.
|
||||
|
||||
When the input source changes, each *index* in the new table is compared with
|
||||
the last input table.
|
||||
|
||||
- For any new index, the `transform` function is ran under a new stable
|
||||
scope to produce a new instance.
|
||||
- For any removed index, the stable scope for that index is destroyed.
|
||||
- Unchanged indexes are untouched.
|
||||
|
||||
The transform function is called only ever *once* for each index in the
|
||||
source table.
|
||||
|
||||
1. First argument is a *source containing the index's value*.
|
||||
2. Second argument is the *index itself*.
|
||||
|
||||
Anytime an existing index's value changes, the transform function is not
|
||||
rerun, instead the source value for that index will update, causing anything
|
||||
depending on it to update too.
|
||||
|
||||
- **Example**
|
||||
|
||||
The intended purpose of this function is to map each index in a table to
|
||||
a UI element.
|
||||
|
||||
```luau
|
||||
type Item = {
|
||||
name: string,
|
||||
icon: number
|
||||
}
|
||||
|
||||
local items = source {} :: () -> Array<Item>
|
||||
|
||||
local displays = indexes(items, function(item, i)
|
||||
return ItemDisplay {
|
||||
Name = function()
|
||||
return i .. ": " .. item().name
|
||||
end,
|
||||
|
||||
Image = function()
|
||||
return "rbxassetid://" .. item().icon
|
||||
end,
|
||||
}
|
||||
end)
|
||||
```
|
||||
|
||||
## values()
|
||||
|
||||
Maps each value in a table source to an object.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function values<KI, VI, VO>(
|
||||
source: () -> Map<KI, VI>,
|
||||
transform: (value: VI, index: () -> KI) -> VO
|
||||
): Array<VO>
|
||||
|
||||
- **Details**
|
||||
|
||||
Returns a source holding an array of instances currently shown.
|
||||
|
||||
When the input source changes, each *value* in the new table is compared with
|
||||
the last input table. Similar to `indexes()` but for values instead of indexes.
|
||||
|
||||
- For any new value, the `transform` function is ran under a new stable
|
||||
scope to produce a new instance.
|
||||
- For any removed value, the stable scope for that value is destroyed.
|
||||
- Unchanged values are untouched.
|
||||
|
||||
The transform function is only ever called *once* for each value in the
|
||||
source table.
|
||||
|
||||
1. First argument is the *value itself*.
|
||||
2. Second argument is a *source containing the value's index*.
|
||||
|
||||
Anytime an existing value's index changes, the transform function is not
|
||||
rerun, instead the source index for that value will update, causing anything
|
||||
depending on it to update too.
|
||||
|
||||
::: warning
|
||||
Having primitive values in the input source table can cause unexpected
|
||||
behavior, as duplicate values can result in multiple tranforms being ran for
|
||||
a single value, meaning there can be multiple source indexes bound to the
|
||||
same UI element. Strict mode has checks for this.
|
||||
:::
|
||||
|
||||
- **Example**
|
||||
|
||||
The intended purpose of this function is to map each value in a table to
|
||||
a UI element.
|
||||
|
||||
```luau
|
||||
type Item = {
|
||||
name: string,
|
||||
icon: number
|
||||
}
|
||||
|
||||
local items = source {} :: () -> Array<Item>
|
||||
|
||||
local displays = values(items, function(item, i)
|
||||
return ItemDisplay {
|
||||
Name = function()
|
||||
return i() .. ": " .. item.Name
|
||||
end
|
||||
|
||||
Image = "rbxassetid://" .. item.icon,
|
||||
}
|
||||
end)
|
||||
```
|
||||
|
||||
- **Extra**
|
||||
|
||||
When should you use `indexes()` and `values()`?
|
||||
|
||||
`values()` should be used when you have a fixed set of objects where the
|
||||
same objects can be re-arranged in the source table. It maps a value to a
|
||||
UI element.
|
||||
|
||||
e.g.
|
||||
- List of all players.
|
||||
- Inventory of items.
|
||||
- Chat message history.
|
||||
- Toast notifications.
|
||||
|
||||
`indexes()` should be used in other cases, especially when your source table
|
||||
has primitive values. It maps an index to a UI element.
|
||||
|
||||
e.g.
|
||||
- List of character or weapon stats.
|
||||
|
||||
In most cases, both functions will appear to have the same behavior.
|
||||
The main difference is performance, picking the right function to use can
|
||||
result in less property updates and less re-renders. One case to note is
|
||||
that `values()` works nicely when animating re-ordering of instances, since
|
||||
the value is not destroyed when indexes are changed, and the source index
|
||||
can be used to animate a change in position for the UI element.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
# Reactivity API: Utility
|
||||
# Reactivity: Utility
|
||||
|
||||
## cleanup()
|
||||
|
||||
Runs a callback anytime a scope is reran or destroyed.
|
||||
Queues a callback to run when a scope is reran or destroyed.
|
||||
|
||||
- **Type**
|
||||
|
||||
```luau
|
||||
function cleanup(callback: () -> ())
|
||||
function cleanup(obj: Destroyable)
|
||||
function cleanup(obj: Disconnectable)
|
||||
function cleanup(v: Function | Disconnectable | Destroyable)
|
||||
|
||||
type Function = () -> ()
|
||||
type Destroyable = { destroy: () -> () }
|
||||
type Disconnectable = { disconnect: () -> () }
|
||||
```
|
||||
|
|
@ -18,20 +17,27 @@ Runs a callback anytime a scope is reran or destroyed.
|
|||
- **Example**
|
||||
|
||||
```luau
|
||||
local data = source(1)
|
||||
local count = source(0)
|
||||
|
||||
effect(function()
|
||||
local label = create "TextLabel" { Text = data() }
|
||||
local destroy = root(function()
|
||||
effect(function()
|
||||
count()
|
||||
|
||||
cleanup(function()
|
||||
label:Destroy()
|
||||
cleanup(function()
|
||||
print "cleaned"
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
-- nothing printed yet
|
||||
count(1) -- prints "cleaned"
|
||||
count(2) -- prints "cleaned"
|
||||
destroy() -- prints "cleaned"
|
||||
```
|
||||
|
||||
## untrack()
|
||||
## untrack() <Badge type="info" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">STABLE</a></Badge>
|
||||
|
||||
Runs a given function in a new stable scope.
|
||||
Runs a function in a new stable scope.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -55,16 +61,15 @@ Runs a given function in a new stable scope.
|
|||
end)
|
||||
|
||||
print(sum()) -- 0
|
||||
b(1)
|
||||
b(1) -- untracked so reactive scope created by derive() does not rerun
|
||||
print(sum()) -- 0
|
||||
a(1)
|
||||
a(1) -- reactive scope created by derive() reruns
|
||||
print(sum()) -- 2
|
||||
```
|
||||
|
||||
## read()
|
||||
|
||||
Utility used to read a value that is either a primitive or a source. Sources
|
||||
read can still be tracked inside a reactive scope.
|
||||
Utility used to read a value that is either a primitive or a source.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -74,8 +79,8 @@ read can still be tracked inside a reactive scope.
|
|||
|
||||
## batch()
|
||||
|
||||
Runs a given function where any source updates made within the function do not
|
||||
trigger effects until after the function finishes running.
|
||||
Runs a function where any source updates made within the function do not
|
||||
trigger effects until after the function ends.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -86,11 +91,29 @@ trigger effects until after the function finishes running.
|
|||
- **Details**
|
||||
|
||||
Improves performance when an effect depends on multiple sources, and those
|
||||
sources need to be updated. Updating those sources inside a batch call will
|
||||
only cause the effect to run once after the batch call ends instead of after
|
||||
each time a source is updated.
|
||||
sources need to be updated.
|
||||
|
||||
## context()
|
||||
- **Example**
|
||||
|
||||
```luau
|
||||
local a = source(0)
|
||||
local b = source(0)
|
||||
|
||||
effect(function()
|
||||
print(a() + b())
|
||||
end)
|
||||
|
||||
-- prints "0"
|
||||
|
||||
batch(function()
|
||||
a(1) -- no print
|
||||
b(2) -- no print
|
||||
end)
|
||||
|
||||
-- prints "3"
|
||||
```
|
||||
|
||||
## context() <Badge type="info" text="STABLE"><a href="/vide/api/reactivity-core#Scopes">STABLE</a></Badge>
|
||||
|
||||
Creates a new context.
|
||||
|
||||
|
|
@ -101,15 +124,17 @@ Creates a new context.
|
|||
|
||||
type Context<T> =
|
||||
() -> T -- get
|
||||
& (T, () -> ()) -> () -- set
|
||||
& <U>(T, () -> U) -> U -- set
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Calling `context()` returns a new context function.
|
||||
Call this function with no arguments to get the context value.
|
||||
Call this function with a value and a callback to set a new context with the
|
||||
given value.
|
||||
Call this function with a value and a function to create a new context with
|
||||
the given value.
|
||||
|
||||
The new context is run under a stable scope.
|
||||
|
||||
- **Example**
|
||||
|
||||
|
|
@ -131,4 +156,3 @@ Creates a new context.
|
|||
end)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -14,25 +14,23 @@ and identifying improper usage.
|
|||
|
||||
Currently, strict mode will:
|
||||
|
||||
1. Run derived sources twice a source updates.
|
||||
2. Run effects twice when a source updates.
|
||||
3. Throw an error if yields occur where they are not allowed.
|
||||
4. Checks for `indexes()` and `values()` returning primitive values.
|
||||
5. Checks for `values()` input having duplicate values.
|
||||
6. Checks for duplicate nested properties at same depth.
|
||||
7. Better error reporting and stack traces + creation traces of property bindings.
|
||||
1. Run reactive scopes twice when a source updates.
|
||||
2. Throw an error if yields occur where they are not allowed.
|
||||
3. Checks for `indexes()` and `values()` outputting primitive values.
|
||||
4. Checks for `values()` input having duplicate values.
|
||||
5. Checks for duplicate nested properties at same depth.
|
||||
6. Better error reporting and stack traces + creation traces of property bindings.
|
||||
|
||||
By rerunning derived sources and effects twice each time they update, it helps
|
||||
ensure that derived source computations are pure, and that any
|
||||
cleanups made in derived sources or effects are done correctly.
|
||||
By rerunning reactive scopes twice each time they update, it helps ensure that
|
||||
computations are pure, and that any cleanup is done correctly.
|
||||
|
||||
Accidental yielding within reactive scopes can break Vide's reactive graph,
|
||||
which strict mode will catch.
|
||||
|
||||
As well as additional safety checks, Vide will dedicate extra resources to
|
||||
recording and better emitting stack traces where errors occur, particularly
|
||||
when binding properties to sources.
|
||||
when implicit effects are created for instance property updating.
|
||||
|
||||
It is recommended to develop UI with strict mode and to disable it when pushing to
|
||||
production. In Roblox, production code compiles at O2 by default, so you don't
|
||||
production. In Roblox, production code compiles at O2 by default, so you do not
|
||||
need to worry about disabling strict mode unless you have manually enabled it.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue