mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Merge branch 'main' of https://github.com/centau/vide
This commit is contained in:
commit
63077355eb
66 changed files with 1741 additions and 1671 deletions
|
|
@ -6,10 +6,16 @@ Vide is heavily inspired by [Solid](https://www.solidjs.com/).
|
|||
|
||||
## Why Vide?
|
||||
|
||||
Vide provides a reactive and declarative API to simplify managing UI.
|
||||
Vide's reactive and declarative API aims to let you program UI as simply as
|
||||
possible, with a strong focus on how data flows through your application.
|
||||
|
||||
Some of the main focuses behind Vide's design choices:
|
||||
Some of Vide's main design choices:
|
||||
|
||||
- Minimal syntax
|
||||
- Complete typechecking
|
||||
- Independence from instances
|
||||
- Syntax minimal.
|
||||
- Data oriented.
|
||||
- Typechecking compatible.
|
||||
- Instance independent.
|
||||
|
||||
Vide's reactivity operates with the concept
|
||||
of scopes which carries a learning curve, though is what makes Vide's minimal
|
||||
syntax possible. The crash course will introduce these concepts gradually.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ destroyed, or when a stable scope is destroyed.
|
|||
local root = vide.root
|
||||
local source = vide.source
|
||||
local effect = vide.effect
|
||||
local cleanup = vide.cleanup
|
||||
|
||||
local count = source(0)
|
||||
|
||||
|
||||
local destroy = root(function()
|
||||
effect(function()
|
||||
local x = count()
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
# Control Flow
|
||||
|
||||
Eventually you may need a way to dynamically create and destroy UI elements
|
||||
resulting from source updates. Vide provides functions to help you do this,
|
||||
known as *control flow* functions.
|
||||
|
||||
These functions return new sources, which hold the instances to be displayed.
|
||||
The new sources can be used in `create()` to update the children of a container
|
||||
instance.
|
||||
|
||||
## indexes()
|
||||
|
||||
`indexes()` *maps* each table index to a new UI element that can
|
||||
update to display the current value at that index. Each table index is given a
|
||||
single corresponding UI element.
|
||||
|
||||
```luau
|
||||
local list = source {
|
||||
"finish the crash course",
|
||||
"star Vide's GitHub"
|
||||
}
|
||||
|
||||
local function TodoList(props: { list: () -> Array<string> })
|
||||
return create "Frame" {
|
||||
create "UIListLayout" {},
|
||||
|
||||
indexes(list, function(todo, i)
|
||||
return create "TextLabel" {
|
||||
Text = function()
|
||||
return i .. ": " .. todo()
|
||||
end,
|
||||
|
||||
LayoutOrder = i
|
||||
}
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
TodoList { list = list }
|
||||
```
|
||||
|
||||
For each index in the given source table, the given function to `indexes()` will
|
||||
be run in a new stable scope with:
|
||||
|
||||
1. a source containing the value at the index
|
||||
2. the index itself
|
||||
|
||||
When the value at an index is changed, the function is not reran. Instead, the
|
||||
given source for that index is updated.
|
||||
|
||||
Any time the input source table is updated, the given function will be ran for
|
||||
any newly added indexes, while any removed indexes (indexes now with a `nil`
|
||||
value), will have its corresponding stable scope destroyed.
|
||||
|
||||
|
||||
|
||||
The reactive graph for the above example:
|
||||
|
||||
```mermaid
|
||||
%%{init: {
|
||||
"theme": "base",
|
||||
"themeVariables": {
|
||||
"primaryColor": "#1B1B1F",
|
||||
"primaryTextColor": "#fff",
|
||||
"primaryBorderColor": "#1B1B1F",
|
||||
"lineColor": "#79B8FF",
|
||||
"tertiaryColor": "#161618",
|
||||
"tertiaryBorderColor": "#1C1C1F"
|
||||
}
|
||||
}}%%
|
||||
|
||||
graph
|
||||
|
||||
subgraph root ["root scope"]
|
||||
direction LR
|
||||
todoList --> indexes -.- subroot1 & subroot2
|
||||
|
||||
subgraph subroot1 ["indexes scope 1"]
|
||||
direction LR
|
||||
value1[todo] --> prop1["prop binding"]
|
||||
end
|
||||
|
||||
subgraph subroot2 ["indexes scope 2"]
|
||||
direction LR
|
||||
value2[todo] --> prop2[prop binding]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
When you edit a table in a source, you must set that table again to actually
|
||||
update the source.
|
||||
|
||||
```luau
|
||||
local src = source { 1, 2 }
|
||||
local data = src()
|
||||
table.insert(data, 3) -- no effects will run
|
||||
src(data) -- effects will run
|
||||
```
|
||||
158
docs/tut/crash-course/11-dynamic-scopes.md
Normal file
158
docs/tut/crash-course/11-dynamic-scopes.md
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# Dynamic Scopes
|
||||
|
||||
Eventually you may need a way to dynamically create and destroy UI elements
|
||||
resulting from source updates. Vide provides functions to help you do this,
|
||||
known as *dynamic scope* functions.
|
||||
|
||||
These functions create and destroy components for you in response to source
|
||||
updates. They return a source containing the created component. This source can
|
||||
be parented as a child which will update the shown children whenever the source
|
||||
updates.
|
||||
|
||||
The simplest example is using `show()`.
|
||||
|
||||
```luau
|
||||
local source = vide.source
|
||||
local create = vide.create
|
||||
local show = vide.show
|
||||
local root = vide.root
|
||||
|
||||
function Button(props: { Text: string, Activated: () -> () })
|
||||
return create "TextButton" {
|
||||
Text = props.Text,
|
||||
Activated = props.Activated
|
||||
}
|
||||
end
|
||||
|
||||
function Menu()
|
||||
return create "TextLabel" {
|
||||
Text = "This is a menu"
|
||||
}
|
||||
end
|
||||
|
||||
function App()
|
||||
local toggled = source(false)
|
||||
|
||||
return create "ScreenGui" {
|
||||
Button {
|
||||
Text = "Toggle Menu",
|
||||
Activated = function()
|
||||
toggled(not toggled())
|
||||
end
|
||||
},
|
||||
|
||||
show(toggled, Menu) -- [!code highlight]
|
||||
}
|
||||
end
|
||||
|
||||
root(function()
|
||||
App().Parent = game.StarterGui
|
||||
end)
|
||||
```
|
||||
|
||||
This is a complete example of rendering UI which has a single button that
|
||||
toggles the opening of a menu.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Another common function is `indexes()`. This function creates a component for
|
||||
each index in a table.
|
||||
|
||||
Each component created is done so in a new and independent stable scope. The
|
||||
indexes of the table are checked each source update to prevent redunant
|
||||
destruction and recreation of UI elements.
|
||||
|
||||
```luau
|
||||
local source = vide.source
|
||||
local create = vide.create
|
||||
local indexes = vide.indexes
|
||||
local root = vide.root
|
||||
|
||||
local function Todo(props: {
|
||||
Text: () -> string,
|
||||
Position: number,
|
||||
Activated: () -> ()
|
||||
})
|
||||
return create "TextButton" {
|
||||
Text = function() return props.Position .. ": " .. props.Text() end,
|
||||
LayoutOrder = props.Position,
|
||||
Activated = Activated
|
||||
}
|
||||
end
|
||||
|
||||
local function TodoList(props: { List: () -> Array<string> })
|
||||
return create "Frame" {
|
||||
create "UIListLayout" {},
|
||||
|
||||
indexes(props.List, function(text, i) -- [!code highlight]
|
||||
return Todo {
|
||||
Text = text,
|
||||
Position = i,
|
||||
Activated = function() -- remove the todo when clicked
|
||||
local list = props.List()
|
||||
table.remove(list, i)
|
||||
props.List(list)
|
||||
end
|
||||
}
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
function App()
|
||||
local list = source {
|
||||
"finish the crash course",
|
||||
"star Vide's GitHub"
|
||||
}
|
||||
|
||||
return create "ScreenGui" {
|
||||
TodoList { List = list },
|
||||
}
|
||||
end
|
||||
|
||||
root(function()
|
||||
App().Parent = game.StarterGui
|
||||
end)
|
||||
```
|
||||
|
||||
The reactive graph for the above example:
|
||||
|
||||
```mermaid
|
||||
%%{init: {
|
||||
"theme": "base",
|
||||
"themeVariables": {
|
||||
"primaryColor": "#111720",
|
||||
"primaryTextColor": "#fff",
|
||||
"primaryBorderColor": "#111720",
|
||||
"lineColor": "#79B8FF",
|
||||
"tertiaryColor": "#0d131b",
|
||||
"tertiaryBorderColor": "#0d131b"
|
||||
}
|
||||
}}%%
|
||||
|
||||
graph
|
||||
|
||||
subgraph root ["root"]
|
||||
direction LR
|
||||
todoList --> indexes -.- subroot1 & subroot2
|
||||
|
||||
subgraph subroot1 ["indexes scope 1"]
|
||||
direction LR
|
||||
value1[todo] --> prop1["prop binding"]
|
||||
end
|
||||
|
||||
subgraph subroot2 ["indexes scope 2"]
|
||||
direction LR
|
||||
value2[todo] --> prop2[prop binding]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
When you edit a table in a source, you must set that table again to actually
|
||||
update the source.
|
||||
|
||||
```luau
|
||||
local src = source { 1, 2 }
|
||||
local data = src()
|
||||
table.insert(data, 3) -- no effects will run
|
||||
src(data) -- effects will run
|
||||
```
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
# Actions
|
||||
|
||||
Actions in Vide are special callbacks that you can pass along with properties,
|
||||
Actions are special callbacks that you can pass along with properties,
|
||||
to run some code on an instance receiving them.
|
||||
|
||||
```luau
|
||||
local action = vide.action
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
```luau
|
||||
=======
|
||||
>>>>>>> 58a31a1b329e922dc86c554e8220012ab7238f1b
|
||||
create "TextLabel" {
|
||||
Text = "test",
|
||||
|
||||
|
|
@ -24,12 +26,13 @@ action used to listen for property changes:
|
|||
|
||||
```luau
|
||||
local action = vide.action
|
||||
local source = vide.source
|
||||
local effect = vide.effect
|
||||
local cleanup = vide.cleanup
|
||||
|
||||
local function changed(prop: string, callback: (new) -> ())
|
||||
local function changed(property: string, callback: (new) -> ())
|
||||
return action(function(instance)
|
||||
local connection = instance:GetPropertyChangedSignal(prop):Connect(function()
|
||||
local connection = instance:GetPropertyChangedSignal(property):Connect(function()
|
||||
callback(instance[property])
|
||||
end)
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ effect(function()
|
|||
print(output())
|
||||
end)
|
||||
|
||||
instance.Text = "foo" -- "foo" will be printed from the effect
|
||||
instance.Text = "foo" -- "foo" will be printed by the effect
|
||||
```
|
||||
|
||||
The source `output` will be updated with the new property value any time it is
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ local count = source(0)
|
|||
|
||||
local ran = 0
|
||||
effect(function()
|
||||
count()
|
||||
ran += 1
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Created by:
|
|||
|
||||
- `root()`
|
||||
- `untrack()`
|
||||
- `switch()`
|
||||
- `show()`
|
||||
- `indexes()`
|
||||
|
||||
Stable scopes do not track sources and never rerun.
|
||||
|
|
@ -47,23 +47,14 @@ Created by:
|
|||
Reactive scopes do track sources and will rerun when those sources update.
|
||||
|
||||
Reactive scopes cannot be created within a reactive scope, but stable scopes
|
||||
can.
|
||||
can be created within a reactive scope.
|
||||
|
||||
## Scope Owners
|
||||
## Scope Cleanup
|
||||
|
||||
A scope created within another scope is *owned* by the other scope, with the
|
||||
exception of the scope created by `root()`.
|
||||
When a scope is rerun or destroyed, all scopes created within it are
|
||||
automatically destroyed.
|
||||
|
||||
When a scope is rerun or destroyed, all scopes owned by it are automatically
|
||||
destroyed.
|
||||
|
||||
`root()` creates a stable scope with no owner, instead it is destroyed manually.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Arbitrary code to run whenever a stable or reactive scope is rerun or destroyed.
|
||||
|
||||
Queue a function to run using `cleanup()`.
|
||||
Any functions queued by `cleanup()` are also ran.
|
||||
|
||||
## Reactive Graph
|
||||
|
||||
|
|
@ -78,7 +69,7 @@ local count = source(0)
|
|||
|
||||
root(function()
|
||||
local text = derive(function()
|
||||
return "count: " .. text()
|
||||
return "count: " .. count()
|
||||
end)
|
||||
|
||||
effect(function()
|
||||
|
|
@ -93,12 +84,12 @@ end)
|
|||
%%{init: {
|
||||
"theme": "base",
|
||||
"themeVariables": {
|
||||
"primaryColor": "#1B1B1F",
|
||||
"primaryColor": "#111720",
|
||||
"primaryTextColor": "#fff",
|
||||
"primaryBorderColor": "#1B1B1F",
|
||||
"primaryBorderColor": "#111720",
|
||||
"lineColor": "#79B8FF",
|
||||
"tertiaryColor": "#161618",
|
||||
"tertiaryBorderColor": "#1C1C1F"
|
||||
"tertiaryColor": "#0d131b",
|
||||
"tertiaryBorderColor": "#202530"
|
||||
}
|
||||
}}%%
|
||||
|
||||
|
|
@ -118,6 +109,5 @@ Notes:
|
|||
- An update to `count` will cause `text` to rerun, which
|
||||
then causes `effect` to rerun.
|
||||
- When the root scope is destroyed, `text` and
|
||||
`effect` will be destroyed alongside it, since they are
|
||||
owned by it. `count` will be untouched and future updates
|
||||
to `count` will have no effect.
|
||||
`effect` will be destroyed alongside it, since they were created within it.
|
||||
`count` will be untouched and future updates to `count` will have no effect.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Effects
|
||||
|
||||
Effects are functions that are ran in response to source updates. They are
|
||||
Effects are functions that are ran in response to source updates.
|
||||
A source and effect is analogous to a signal and connection.
|
||||
|
||||
Effects are created using `effect()`.
|
||||
|
|
@ -23,7 +23,10 @@ count(1)
|
|||
Any source read inside an effect is tracked and will rerun the effect when
|
||||
that source is updated.
|
||||
|
||||
Derived sources are also tracked, it doesn't matter how deeply nested
|
||||
The effect runs its callback once immediately to initially figure out what
|
||||
sources are being read.
|
||||
|
||||
Derived sources are also tracked, it does not matter how deeply nested
|
||||
inside a function a source is.
|
||||
|
||||
```luau
|
||||
|
|
@ -47,3 +50,22 @@ count(2)
|
|||
|
||||
If a source is updated with the same value it already had, it will not rerun
|
||||
effects depending on it.
|
||||
|
||||
You can also read from a source within an effect without the effect tracking it.
|
||||
|
||||
```luau
|
||||
local source = vide.source
|
||||
local effect = vide.effect
|
||||
local untrack = vide.untrack
|
||||
|
||||
local a = source(0)
|
||||
local b = source(0)
|
||||
|
||||
effect(function()
|
||||
print(`a: {a()} b: {untrack(b)}`)
|
||||
end)
|
||||
|
||||
a(1) -- prints "a: 1 b: 0"
|
||||
b(1) -- prints nothing
|
||||
a(2) -- prints "a: 2 b: 1"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -7,38 +7,39 @@ But the disconnecting of many signals and connections is tedious and verbose.
|
|||
Vide instead operates on the concept of scopes which provides a much cleaner
|
||||
API, given that you follow a few rules.
|
||||
|
||||
Scopes come in two flavors; stable and reactive.
|
||||
Thre are two types of scopes: stable and reactive.
|
||||
|
||||
- All scopes must be created within another scope with the exception of `root()`
|
||||
- Stable scopes never rerun
|
||||
- Reactive scopes can rerun
|
||||
- A reactive scope cannot be created within another reactive scope
|
||||
- A scope must be created within another scope.
|
||||
- Stable scopes never rerun.
|
||||
- Reactive scopes can rerun.
|
||||
- A reactive scope cannot be created within another reactive scope, only within
|
||||
a stable scope.
|
||||
|
||||
An exception to the first rule is `root()`, which creates the initial scope that
|
||||
you destroy manually with a destructor function it returns.
|
||||
|
||||
`effect()` creates a reactive scope.
|
||||
`root()` creates a stable scope.
|
||||
`effect()` creates a reactive scope.
|
||||
|
||||
Whenever a scope is destroyed, any scope created within that scope is also
|
||||
destroyed, and so on. This is why all scopes must be created within another
|
||||
scope, except `root()` which is used to create the initial scope that you can
|
||||
manually destroy.
|
||||
destroyed, and so on.
|
||||
|
||||
```luau
|
||||
local root = vide.root
|
||||
local source = vide.source
|
||||
local effect = vide.effect
|
||||
|
||||
local function setup()
|
||||
local count = source(0)
|
||||
local count = source(0)
|
||||
|
||||
local function setup()
|
||||
effect(function()
|
||||
print(count())
|
||||
end)
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
setup() -- will error since effect() tries to create a reactive scope outside of a stable scope
|
||||
setup() -- error, effect() tried to create a reactive scope with no stable scope
|
||||
|
||||
<<<<<<< HEAD
|
||||
local count = root(setup) -- ok since effect() was called within a stable scope
|
||||
count(1) -- prints "1"
|
||||
```
|
||||
|
|
@ -57,12 +58,16 @@ local function setup()
|
|||
end
|
||||
|
||||
local destroy, count = root(setup)
|
||||
=======
|
||||
local destroy = root(setup) -- ok since effect() was called in a stable scope
|
||||
>>>>>>> 58a31a1b329e922dc86c554e8220012ab7238f1b
|
||||
|
||||
count(1) -- prints "1"
|
||||
count(2) -- prints "2"
|
||||
|
||||
destroy()
|
||||
|
||||
count(2) -- effect is destroyed; no longer prints
|
||||
count(3) -- reactive scope created by effect() is destroyed, it does not rerun
|
||||
```
|
||||
|
||||
Vide's reactivity can be represented graphically, as a *reactive graph*.
|
||||
|
|
@ -73,12 +78,12 @@ The reactive graph for the above example looks like so:
|
|||
%%{init: {
|
||||
"theme": "base",
|
||||
"themeVariables": {
|
||||
"primaryColor": "#1B1B1F",
|
||||
"primaryColor": "#111720",
|
||||
"primaryTextColor": "#fff",
|
||||
"primaryBorderColor": "#1B1B1F",
|
||||
"primaryBorderColor": "#111720",
|
||||
"lineColor": "#79B8FF",
|
||||
"tertiaryColor": "#161618",
|
||||
"tertiaryBorderColor": "#161618"
|
||||
"tertiaryColor": "#0d131b",
|
||||
"tertiaryBorderColor": "#0d131b"
|
||||
}
|
||||
}}%%
|
||||
|
||||
|
|
@ -90,7 +95,7 @@ subgraph root
|
|||
end
|
||||
```
|
||||
|
||||
When the stable `root()` is destroyed, the reactive `effect()`
|
||||
When the stable `root()` scope is destroyed, the reactive `effect()`
|
||||
scope will also be destroyed since it was created within it.
|
||||
|
||||
This is important because you may have an effect that updates the property of a
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
# Stateful Components
|
||||
# Reactive Components
|
||||
|
||||
Stateful components in Vide are created using sources and effects - sources to
|
||||
Reactive components in Vide are created using sources and effects - sources to
|
||||
store the data, and effects to display the data.
|
||||
|
||||
<<<<<<< HEAD:docs/tut/crash-course/7-stateful-component.md
|
||||
## Internal State
|
||||
|
||||
=======
|
||||
>>>>>>> 58a31a1b329e922dc86c554e8220012ab7238f1b:docs/tut/crash-course/7-reactive-component.md
|
||||
```luau
|
||||
local create = vide.create
|
||||
local source = vide.source
|
||||
|
|
@ -33,19 +36,17 @@ its internal count, and automatically update its text to reflect that count.
|
|||
Each instance of `Counter()` will maintain its own independent count, since the
|
||||
count source is created inside the component.
|
||||
|
||||
## External State
|
||||
|
||||
External sources can also be passed into components for them to use.
|
||||
|
||||
```luau
|
||||
<<<<<<< HEAD:docs/tut/crash-course/7-stateful-component.md
|
||||
local function Counter(props: { count: () -> number })
|
||||
=======
|
||||
local function CountDisplay(props: { count: () -> number })
|
||||
>>>>>>> 58a31a1b329e922dc86c554e8220012ab7238f1b:docs/tut/crash-course/7-reactive-component.md
|
||||
local count = props.count
|
||||
|
||||
local instance = create "TextButton" {
|
||||
Activated = function()
|
||||
count(count() + 1)
|
||||
end
|
||||
}
|
||||
local instance = create "TextLabel" {}
|
||||
|
||||
effect(function()
|
||||
instance.Text = "count: " .. count()
|
||||
|
|
@ -56,11 +57,11 @@ end
|
|||
|
||||
local count = source(0)
|
||||
|
||||
Counter {
|
||||
CountDisplay {
|
||||
count = count
|
||||
}
|
||||
|
||||
count(1) -- the Counter component will update to display this count
|
||||
count(1) -- the CountDisplay component will update to display this count
|
||||
```
|
||||
|
||||
Sources can be created internally or passed in from externally, there are no
|
||||
|
|
@ -3,7 +3,13 @@
|
|||
Explicitly creating effects to update properties is tedious. You can
|
||||
*implicitly* create an effect to update properties instead.
|
||||
|
||||
<<<<<<< HEAD
|
||||
```luau
|
||||
=======
|
||||
::: code-group
|
||||
|
||||
```luau [Implicit Effect]
|
||||
>>>>>>> 58a31a1b329e922dc86c554e8220012ab7238f1b
|
||||
local create = vide.create
|
||||
local source = vide.source
|
||||
|
||||
|
|
@ -22,6 +28,30 @@ local function Counter()
|
|||
end
|
||||
```
|
||||
|
||||
```luau [Explicit Effect]
|
||||
local create = vide.create
|
||||
local source = vide.source
|
||||
local effect = vide.effect
|
||||
|
||||
local function Counter()
|
||||
local count = source(0)
|
||||
|
||||
local instance = create "TextButton" {
|
||||
Activated = function()
|
||||
count(count() + 1)
|
||||
end
|
||||
}
|
||||
|
||||
effect(function()
|
||||
instance.Text = "count: " .. count()
|
||||
end)
|
||||
|
||||
return instance
|
||||
end
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
This example is equivalent to the example seen on the previous page.
|
||||
|
||||
Instead of explicitly creating an effect, assigning a (non-event) property a
|
||||
|
|
@ -46,12 +76,12 @@ local function List(props: { children: () -> { Instance } })
|
|||
}
|
||||
end
|
||||
|
||||
local list = List { children = items } -- creates a list with a single text label "A"
|
||||
local list = List { children = items } -- creates a list with text label "A"
|
||||
|
||||
items {
|
||||
create "TextLabel" { Text = "B" },
|
||||
create "TextLabel" { Text = "C" }
|
||||
}
|
||||
|
||||
-- this will automatically unparent the text label "A", and parent the labels "B" and "C"
|
||||
-- this will automatically unparent text label "A", and parent labels "B" and "C"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ effect(function() text() end)
|
|||
count(1) -- prints "ran" x1
|
||||
```
|
||||
|
||||
`derive()` must also be called within a stable scope, just like `effect()`.
|
||||
Because `derive()` creates a reactive scope, it must be called within a stable
|
||||
scope, just like `effect()`.
|
||||
|
||||
If the recalculated value is the same as the old value, the derived source will
|
||||
not rerun the effects using it.
|
||||
|
|
@ -68,12 +69,12 @@ The reactive graph for the above example:
|
|||
%%{init: {
|
||||
"theme": "base",
|
||||
"themeVariables": {
|
||||
"primaryColor": "#1B1B1F",
|
||||
"primaryColor": "#111720",
|
||||
"primaryTextColor": "#fff",
|
||||
"primaryBorderColor": "#1B1B1F",
|
||||
"primaryBorderColor": "#111720",
|
||||
"lineColor": "#79B8FF",
|
||||
"tertiaryColor": "#161618",
|
||||
"tertiaryBorderColor": "#161618"
|
||||
"tertiaryColor": "#0d131b",
|
||||
"tertiaryBorderColor": "#0d131b"
|
||||
}
|
||||
}}%%
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ end
|
|||
```
|
||||
|
||||
Deriving a source in this manner is similar to creating an effect to update
|
||||
another source. You should never manually do this using an effect however.
|
||||
another source. You should avoid doing this using an effect however.
|
||||
Improper usage could accidently create infinite loops in the reactive graph.
|
||||
Always favour deriving when you need one source to update based on another
|
||||
source.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue