@lightningjs/blits 1.30.0 → 1.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +7 -7
- package/.eslintignore +1 -1
- package/.eslintrc.cjs +65 -65
- package/.github/workflows/comment-lint-results.yml +124 -124
- package/.github/workflows/comment-test-results.yml +108 -108
- package/.github/workflows/deploy-docs.yml +27 -27
- package/.github/workflows/run-blits-tests.yml +141 -141
- package/.github/workflows/run-lint.yml +127 -127
- package/.husky/pre-commit +1 -1
- package/.vscode/extensions.json +7 -7
- package/.vscode/settings.json +9 -9
- package/CHANGELOG.md +1019 -1005
- package/COPYING +1 -0
- package/LICENSE +202 -202
- package/NOTICE +12 -12
- package/README.md +33 -33
- package/bin/index.js +8 -8
- package/blits.d.ts +6 -6
- package/docs/README.md +19 -19
- package/docs/_sidebar.md +37 -37
- package/docs/built-in/directives.md +50 -50
- package/docs/built-in/for-loop.md +203 -203
- package/docs/built-in/layout.md +168 -168
- package/docs/components/component_state.md +90 -90
- package/docs/components/computed_properties.md +45 -45
- package/docs/components/lifecycle_events.md +42 -42
- package/docs/components/methods.md +45 -45
- package/docs/components/props.md +56 -56
- package/docs/components/user_input.md +186 -186
- package/docs/components/utility_methods.md +320 -320
- package/docs/components/watchers.md +34 -34
- package/docs/essentials/application_root.md +19 -19
- package/docs/essentials/components.md +68 -68
- package/docs/essentials/displaying_images.md +67 -67
- package/docs/essentials/displaying_text.md +135 -135
- package/docs/essentials/element_attributes.md +195 -195
- package/docs/essentials/settings.md +117 -117
- package/docs/essentials/template_syntax.md +83 -83
- package/docs/getting_started/file_structure.md +58 -58
- package/docs/getting_started/getting_started.md +45 -45
- package/docs/getting_started/intro.md +20 -20
- package/docs/index.html +47 -47
- package/docs/performance/lazy-loading.md +161 -161
- package/docs/plugins/global_app_state.md +98 -98
- package/docs/plugins/language.md +172 -172
- package/docs/plugins/text-to-speech-announcer.md +119 -119
- package/docs/plugins/theme.md +176 -176
- package/docs/router/basics.md +175 -175
- package/docs/router/hooks.md +70 -70
- package/docs/router/transitions.md +146 -146
- package/docs/sidebar.json +171 -171
- package/docs/transitions_animations/transitions.md +150 -150
- package/index.d.ts +1099 -1099
- package/index.js +28 -28
- package/jsconfig.json +12 -12
- package/package.json +56 -56
- package/public/assets/fps_sprite.base64.js +1 -1
- package/scripts/postpublish.js +59 -59
- package/scripts/prepublishOnly.js +84 -84
- package/scripts/prepush.js +78 -78
- package/src/announcer/announcer.js +162 -162
- package/src/announcer/speechSynthesis.js +107 -107
- package/src/application.js +100 -100
- package/src/component/base/announcer.js +27 -27
- package/src/component/base/events.js +69 -69
- package/src/component/base/index.js +33 -33
- package/src/component/base/methods.js +244 -244
- package/src/component/base/router.js +41 -41
- package/src/component/base/timeouts_intervals.js +99 -99
- package/src/component/base/utils.js +72 -72
- package/src/component/setup/computed.js +48 -48
- package/src/component/setup/index.js +62 -62
- package/src/component/setup/input.js +30 -30
- package/src/component/setup/methods.js +37 -37
- package/src/component/setup/props.js +62 -62
- package/src/component/setup/props.test.js +238 -238
- package/src/component/setup/routes.js +42 -42
- package/src/component/setup/state.js +59 -59
- package/src/component/setup/watch.js +35 -35
- package/src/component.js +437 -437
- package/src/component.test.js +388 -388
- package/src/components/Circle.js +73 -73
- package/src/components/Circle.orig.js +31 -31
- package/src/components/FPScounter.js +1510 -1510
- package/src/components/FPScounter.orig.js +121 -121
- package/src/components/RouterView.js +81 -81
- package/src/components/RouterView.orig.js +54 -54
- package/src/components/Sprite.js +94 -94
- package/src/components/Sprite.orig.js +58 -58
- package/src/components/index.js +28 -28
- package/src/components/index.orig.js +28 -28
- package/src/constants.js +21 -21
- package/src/engine.js +1 -1
- package/src/engines/L3/element.js +744 -744
- package/src/engines/L3/element.test.js +579 -579
- package/src/engines/L3/fontLoader.js +38 -38
- package/src/engines/L3/index.js +7 -7
- package/src/engines/L3/launch.js +123 -123
- package/src/engines/L3/shaderLoader.js +12 -12
- package/src/engines/index.js +1 -1
- package/src/focus.js +90 -90
- package/src/helpers/deepEqualArray.js +50 -50
- package/src/helpers/deepEqualArray.test.js +127 -127
- package/src/helpers/fetchJson.js +34 -34
- package/src/helpers/sequence.js +26 -26
- package/src/launch.js +123 -123
- package/src/lib/blitsfileconverter/blitsfileconverter.js +52 -52
- package/src/lib/codegenerator/generator.js +788 -788
- package/src/lib/codegenerator/generator.test.js +3801 -3801
- package/src/lib/colors/colors.js +92 -92
- package/src/lib/colors/colors.test.js +290 -290
- package/src/lib/colors/htmlColors.js +168 -168
- package/src/lib/componentId.js +49 -49
- package/src/lib/componentId.test.js +84 -84
- package/src/lib/eventListeners.js +123 -123
- package/src/lib/eventListeners.test.js +236 -236
- package/src/lib/hooks.js +59 -59
- package/src/lib/lifecycle.js +85 -85
- package/src/lib/log.js +117 -117
- package/src/lib/precompiler/precompiler.js +73 -73
- package/src/lib/reactivity/effect.js +93 -93
- package/src/lib/reactivity/effect.test.js +35 -35
- package/src/lib/reactivity/reactive.js +208 -208
- package/src/lib/reactivity/reactive.test.js +27 -27
- package/src/lib/reactivityguard/computedprops.js +218 -218
- package/src/lib/symbols.js +108 -108
- package/src/lib/templateparser/parser.js +386 -386
- package/src/lib/templateparser/parser.test.js +1411 -1411
- package/src/lib/utils.js +27 -27
- package/src/plugin.js +27 -27
- package/src/plugins/appstate.js +26 -26
- package/src/plugins/index.js +20 -20
- package/src/plugins/language.js +152 -152
- package/src/plugins/log.js +25 -25
- package/src/plugins/theme.js +94 -94
- package/src/router/router.js +514 -514
- package/src/router/router.test.js +473 -473
- package/src/router/transitions/fadeIn.js +27 -27
- package/src/router/transitions/fadeInOut.js +33 -33
- package/src/router/transitions/index.js +21 -21
- package/src/router/transitions/slideIn.js +28 -28
- package/src/router/transitions/slideInOut.js +33 -33
- package/src/settings.js +40 -40
- package/vite/blitsFileConverter.js +67 -67
- package/vite/index.js +28 -28
- package/vite/msdfGenerator.js +269 -269
- package/vite/preCompiler.js +42 -42
- package/vite/reactivityGuard.js +45 -45
- package/vscode/data/template-attributes.json +589 -589
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
# Lazy Loading with the :range Parameter
|
|
2
|
-
|
|
3
|
-
The for-loop in Blits comes with a [`:range` parameter](../built-in/for-loop.html#using-the-range-attribute) that allows you to render only a portion of an array rather than all the items.
|
|
4
|
-
|
|
5
|
-
This `:range` parameter can also be used to easily implement an efficient form of _lazy loading_. Lazy loading is a crucial concept for performance in TV applications where rails can contain hundreds of items, but only a small subset is visible at any time.
|
|
6
|
-
|
|
7
|
-
## Basic range implementation
|
|
8
|
-
|
|
9
|
-
For the basic syntax of the `:range` attribute, we typically set dynamic `from` and `to` values, which define the subset of items to display.
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
<Tile :for="(item, index) in $items" :range="{from: $from, to: $to}" />
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
A full example of a Rail component with a range would look something like this:
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
export default Blits.Component('RangedRail', {
|
|
19
|
-
template: `
|
|
20
|
-
<Element :x.transition="0 - $focused * 300">
|
|
21
|
-
<Tile
|
|
22
|
-
:for="(item, index) in $items"
|
|
23
|
-
:range="{from: $range, to: $range + 7}"
|
|
24
|
-
:key="$item.id"
|
|
25
|
-
:focused="$focused"
|
|
26
|
-
w="300"
|
|
27
|
-
h="200"
|
|
28
|
-
:x="$index * 320"
|
|
29
|
-
/>
|
|
30
|
-
</Element>
|
|
31
|
-
`,
|
|
32
|
-
state() {
|
|
33
|
-
return {
|
|
34
|
-
range: 0,
|
|
35
|
-
focused: 0,
|
|
36
|
-
items: [] // Array of 100+ items
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
input: {
|
|
40
|
-
right() {
|
|
41
|
-
this.focus = Math.min(this.focus + 1, items.length)
|
|
42
|
-
this.range++
|
|
43
|
-
},
|
|
44
|
-
left() {
|
|
45
|
-
this.focus = Math.max(this.focus - 1, 0)
|
|
46
|
-
this.range--
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Benefits of this approach are:
|
|
53
|
-
|
|
54
|
-
- **Selective Rendering**: Only items within the specified range are actually created as elements
|
|
55
|
-
- **Performance Optimization**: Reduces memory usage and improves rendering performance
|
|
56
|
-
- **Dynamic Range Updates**: The range can be computed based on user interaction and scroll position
|
|
57
|
-
|
|
58
|
-
A downside of this approach is that, as we scroll we are also **destroying** components that are out of range. And we may need those
|
|
59
|
-
same items when we scroll back (and thus recreate them). On top of that, destroying Components and Elements also comes at a cost.
|
|
60
|
-
|
|
61
|
-
## Lazy loading with the range attribute
|
|
62
|
-
|
|
63
|
-
We can solve the problem of destroying Components that we may want to use again by slightly changing the logic of the Rail component.
|
|
64
|
-
|
|
65
|
-
1) We set `from: 0`, to ensure we always start from the first item (and _keep_ the first items)
|
|
66
|
-
2) We use `to: $range + 7` to render up to the current position plus a lookahead buffer
|
|
67
|
-
3) The `$range` value tracks how far the user has navigated through the rail, but it doesn't decrement when navigating back
|
|
68
|
-
|
|
69
|
-
With these changes a full example of a LazyRail component would look something like this:
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
export default Blits.Component('LazyRail', {
|
|
73
|
-
template: `
|
|
74
|
-
<Element :x.transition="0 - $focused * 300">
|
|
75
|
-
<Tile
|
|
76
|
-
:for="(item, index) in $items"
|
|
77
|
-
:range="{from: 0, to: $range + 7}"
|
|
78
|
-
:key="$item.id"
|
|
79
|
-
w="300"
|
|
80
|
-
h="200"
|
|
81
|
-
:x="$index * 320"
|
|
82
|
-
/>
|
|
83
|
-
</Element>
|
|
84
|
-
`,
|
|
85
|
-
state() {
|
|
86
|
-
return {
|
|
87
|
-
range: 0,
|
|
88
|
-
items: [] // Array of 100+ items
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
input: {
|
|
92
|
-
right() {
|
|
93
|
-
this.focus = Math.min(this.focus + 1, items.length)
|
|
94
|
-
// push the range update to the next tick to spread out the work
|
|
95
|
-
// and ease the CPU a bit
|
|
96
|
-
this.$setTimeout(() => this.range = this.focus)
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
left() {
|
|
100
|
-
this.focus = Math.max(this.focus - 1, 0)
|
|
101
|
-
// we don't decrement the range when scrolling back to keep components alive
|
|
102
|
-
// this.range--
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Performance Benefits
|
|
109
|
-
|
|
110
|
-
Properly applying the range attribute provides **Memory Efficiency**:
|
|
111
|
-
|
|
112
|
-
- Instead of creating 100+ elements, only ~8-15 are active
|
|
113
|
-
- Reduces GPU memory usage on constrained TV hardware
|
|
114
|
-
- Lower overall memory footprint
|
|
115
|
-
|
|
116
|
-
It also is beneficial for **Faster Rendering**
|
|
117
|
-
|
|
118
|
-
- Initial page load only renders visible items
|
|
119
|
-
- Scroll performance improves as fewer elements need updates
|
|
120
|
-
- Reduced layout calculations
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
It **optimizes bandwidth**
|
|
124
|
-
|
|
125
|
-
- Images and assets only load for rendered items
|
|
126
|
-
- Reduces network requests on page load
|
|
127
|
-
- Progressive content loading
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
### Alpha Transitions
|
|
131
|
-
|
|
132
|
-
For a smoother experience you consider applying an alpha transition, that fades out items at the end of the rang.e
|
|
133
|
-
|
|
134
|
-
```js
|
|
135
|
-
:alpha.transition="$index <= $range ? 1 : ($index <= $range + 3 ? 0.8 : 0.6)"
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
This creates a dimming effect for previously viewed items while maintaining full opacity for the current and upcoming items.
|
|
139
|
-
|
|
140
|
-
## Best Practices
|
|
141
|
-
|
|
142
|
-
### Buffer Size
|
|
143
|
-
|
|
144
|
-
Use a buffer of 5-10 items ahead of current position:
|
|
145
|
-
|
|
146
|
-
```js
|
|
147
|
-
// Conservative buffer for low-end devices
|
|
148
|
-
:range="{from: $currentIndex - 1, to: $currentIndex + 6}"
|
|
149
|
-
|
|
150
|
-
// Larger buffer for smoother experience
|
|
151
|
-
:range="{from: $currentIndex - 2, to: $currentIndex + 10}"
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Performance Impact
|
|
155
|
-
|
|
156
|
-
On typical TV hardware:
|
|
157
|
-
|
|
158
|
-
- **Memory Usage**: 70-80% reduction compared to full rendering
|
|
159
|
-
- **Initial Load Time**: 3-5x faster page initialization
|
|
160
|
-
- **Scroll Performance**: Consistent fps maintained vs potential frame drops
|
|
161
|
-
- **Network Requests**: Reduced by 80-90% on initial load
|
|
1
|
+
# Lazy Loading with the :range Parameter
|
|
2
|
+
|
|
3
|
+
The for-loop in Blits comes with a [`:range` parameter](../built-in/for-loop.html#using-the-range-attribute) that allows you to render only a portion of an array rather than all the items.
|
|
4
|
+
|
|
5
|
+
This `:range` parameter can also be used to easily implement an efficient form of _lazy loading_. Lazy loading is a crucial concept for performance in TV applications where rails can contain hundreds of items, but only a small subset is visible at any time.
|
|
6
|
+
|
|
7
|
+
## Basic range implementation
|
|
8
|
+
|
|
9
|
+
For the basic syntax of the `:range` attribute, we typically set dynamic `from` and `to` values, which define the subset of items to display.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
<Tile :for="(item, index) in $items" :range="{from: $from, to: $to}" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
A full example of a Rail component with a range would look something like this:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
export default Blits.Component('RangedRail', {
|
|
19
|
+
template: `
|
|
20
|
+
<Element :x.transition="0 - $focused * 300">
|
|
21
|
+
<Tile
|
|
22
|
+
:for="(item, index) in $items"
|
|
23
|
+
:range="{from: $range, to: $range + 7}"
|
|
24
|
+
:key="$item.id"
|
|
25
|
+
:focused="$focused"
|
|
26
|
+
w="300"
|
|
27
|
+
h="200"
|
|
28
|
+
:x="$index * 320"
|
|
29
|
+
/>
|
|
30
|
+
</Element>
|
|
31
|
+
`,
|
|
32
|
+
state() {
|
|
33
|
+
return {
|
|
34
|
+
range: 0,
|
|
35
|
+
focused: 0,
|
|
36
|
+
items: [] // Array of 100+ items
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
input: {
|
|
40
|
+
right() {
|
|
41
|
+
this.focus = Math.min(this.focus + 1, items.length)
|
|
42
|
+
this.range++
|
|
43
|
+
},
|
|
44
|
+
left() {
|
|
45
|
+
this.focus = Math.max(this.focus - 1, 0)
|
|
46
|
+
this.range--
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Benefits of this approach are:
|
|
53
|
+
|
|
54
|
+
- **Selective Rendering**: Only items within the specified range are actually created as elements
|
|
55
|
+
- **Performance Optimization**: Reduces memory usage and improves rendering performance
|
|
56
|
+
- **Dynamic Range Updates**: The range can be computed based on user interaction and scroll position
|
|
57
|
+
|
|
58
|
+
A downside of this approach is that, as we scroll we are also **destroying** components that are out of range. And we may need those
|
|
59
|
+
same items when we scroll back (and thus recreate them). On top of that, destroying Components and Elements also comes at a cost.
|
|
60
|
+
|
|
61
|
+
## Lazy loading with the range attribute
|
|
62
|
+
|
|
63
|
+
We can solve the problem of destroying Components that we may want to use again by slightly changing the logic of the Rail component.
|
|
64
|
+
|
|
65
|
+
1) We set `from: 0`, to ensure we always start from the first item (and _keep_ the first items)
|
|
66
|
+
2) We use `to: $range + 7` to render up to the current position plus a lookahead buffer
|
|
67
|
+
3) The `$range` value tracks how far the user has navigated through the rail, but it doesn't decrement when navigating back
|
|
68
|
+
|
|
69
|
+
With these changes a full example of a LazyRail component would look something like this:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
export default Blits.Component('LazyRail', {
|
|
73
|
+
template: `
|
|
74
|
+
<Element :x.transition="0 - $focused * 300">
|
|
75
|
+
<Tile
|
|
76
|
+
:for="(item, index) in $items"
|
|
77
|
+
:range="{from: 0, to: $range + 7}"
|
|
78
|
+
:key="$item.id"
|
|
79
|
+
w="300"
|
|
80
|
+
h="200"
|
|
81
|
+
:x="$index * 320"
|
|
82
|
+
/>
|
|
83
|
+
</Element>
|
|
84
|
+
`,
|
|
85
|
+
state() {
|
|
86
|
+
return {
|
|
87
|
+
range: 0,
|
|
88
|
+
items: [] // Array of 100+ items
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
input: {
|
|
92
|
+
right() {
|
|
93
|
+
this.focus = Math.min(this.focus + 1, items.length)
|
|
94
|
+
// push the range update to the next tick to spread out the work
|
|
95
|
+
// and ease the CPU a bit
|
|
96
|
+
this.$setTimeout(() => this.range = this.focus)
|
|
97
|
+
|
|
98
|
+
},
|
|
99
|
+
left() {
|
|
100
|
+
this.focus = Math.max(this.focus - 1, 0)
|
|
101
|
+
// we don't decrement the range when scrolling back to keep components alive
|
|
102
|
+
// this.range--
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Performance Benefits
|
|
109
|
+
|
|
110
|
+
Properly applying the range attribute provides **Memory Efficiency**:
|
|
111
|
+
|
|
112
|
+
- Instead of creating 100+ elements, only ~8-15 are active
|
|
113
|
+
- Reduces GPU memory usage on constrained TV hardware
|
|
114
|
+
- Lower overall memory footprint
|
|
115
|
+
|
|
116
|
+
It also is beneficial for **Faster Rendering**
|
|
117
|
+
|
|
118
|
+
- Initial page load only renders visible items
|
|
119
|
+
- Scroll performance improves as fewer elements need updates
|
|
120
|
+
- Reduced layout calculations
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
It **optimizes bandwidth**
|
|
124
|
+
|
|
125
|
+
- Images and assets only load for rendered items
|
|
126
|
+
- Reduces network requests on page load
|
|
127
|
+
- Progressive content loading
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### Alpha Transitions
|
|
131
|
+
|
|
132
|
+
For a smoother experience you consider applying an alpha transition, that fades out items at the end of the rang.e
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
:alpha.transition="$index <= $range ? 1 : ($index <= $range + 3 ? 0.8 : 0.6)"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This creates a dimming effect for previously viewed items while maintaining full opacity for the current and upcoming items.
|
|
139
|
+
|
|
140
|
+
## Best Practices
|
|
141
|
+
|
|
142
|
+
### Buffer Size
|
|
143
|
+
|
|
144
|
+
Use a buffer of 5-10 items ahead of current position:
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
// Conservative buffer for low-end devices
|
|
148
|
+
:range="{from: $currentIndex - 1, to: $currentIndex + 6}"
|
|
149
|
+
|
|
150
|
+
// Larger buffer for smoother experience
|
|
151
|
+
:range="{from: $currentIndex - 2, to: $currentIndex + 10}"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Performance Impact
|
|
155
|
+
|
|
156
|
+
On typical TV hardware:
|
|
157
|
+
|
|
158
|
+
- **Memory Usage**: 70-80% reduction compared to full rendering
|
|
159
|
+
- **Initial Load Time**: 3-5x faster page initialization
|
|
160
|
+
- **Scroll Performance**: Consistent fps maintained vs potential frame drops
|
|
161
|
+
- **Network Requests**: Reduced by 80-90% on initial load
|
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
# Global App State plugin
|
|
2
|
-
|
|
3
|
-
Each Blits Component has its own, internal component state that is reactive and can automatically trigger updates in the template upon changes. The internal state is fully encapsulated, which ensures predictable component state and promotes a pattern of clear separation of concerns.
|
|
4
|
-
|
|
5
|
-
But a Component usually doesn't live on its own, instead it's part of a bigger App. And there may arise a need for components to exchange data - intercomponent communication in other words.
|
|
6
|
-
|
|
7
|
-
Blits offers the option to _emit_ and _listen_ to events, as explained in the section on Blits [utility methods](../components/utility_methods.md). For simple use cases, this is a convenient method to pass data along. But when used extensively, it may be easy to lose track of data flows.
|
|
8
|
-
|
|
9
|
-
For more advanced cases, Blits offers an optional Global App State plugin that will act as a global state store that all components have direct access to. It's a simple implementation, focused on providing a _performant_ and _easy to use_ solution for global state. It's not a full flux / redux style state management solution, as we know from experience that these solutions (while very useful and cool), may lead to performance issues on low-end devices.
|
|
10
|
-
|
|
11
|
-
## Registering the plugin
|
|
12
|
-
|
|
13
|
-
The Global App state plugin is provided in the core Blits package, but as it's an _optional_ plugin it first needs to be registered.
|
|
14
|
-
|
|
15
|
-
The plugin can be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
|
|
16
|
-
|
|
17
|
-
Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method.
|
|
18
|
-
|
|
19
|
-
```js
|
|
20
|
-
// index.js
|
|
21
|
-
|
|
22
|
-
import Blits from '@lightningjs/blits'
|
|
23
|
-
// import the app state plugin
|
|
24
|
-
import { appState } from '@lightningjs/blits/plugins'
|
|
25
|
-
|
|
26
|
-
import App from './App.js'
|
|
27
|
-
|
|
28
|
-
// Use the Blits App State plugin
|
|
29
|
-
Blits.Plugin(appState, {
|
|
30
|
-
loggedIn: false,
|
|
31
|
-
user: {
|
|
32
|
-
id: null,
|
|
33
|
-
name: '',
|
|
34
|
-
lastname: ''
|
|
35
|
-
},
|
|
36
|
-
languages: ['en', 'nl', 'pt', 'es'],
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Blits.Launch(App, 'app', {
|
|
41
|
-
// launch settings
|
|
42
|
-
})
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### State object
|
|
46
|
-
|
|
47
|
-
When registering the Global App State plugin, you pass it a state object as the second argument. This is a plain object literal that will be converted into a _reactive_ object, and is used to keep track of the global state variables.
|
|
48
|
-
|
|
49
|
-
The newly created Global App state works exactly the same as an internal Component state. You can read values and you can directly change values. And when you do change a value, it automatically triggers reactive updates. Either via reactive attributes in the template, or in the form of watchers / computed values in the Component logic.
|
|
50
|
-
|
|
51
|
-
### Using global app state in a Component
|
|
52
|
-
|
|
53
|
-
Any variable in the Global App state can be used directly in the template, much like a local Component state. Changing values in the global app state also works exactly the same as updating the internal component state.
|
|
54
|
-
|
|
55
|
-
```js
|
|
56
|
-
Blits.Component('MyComponent', {
|
|
57
|
-
template: `
|
|
58
|
-
<Element>
|
|
59
|
-
<Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
|
|
60
|
-
</Element>
|
|
61
|
-
`,
|
|
62
|
-
input: {
|
|
63
|
-
enter() {
|
|
64
|
-
this.$appState.user.name = 'John'
|
|
65
|
-
this.$appState.loggedIn = true
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
})
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Note that in the template definition, 2 consecutive dollars signs are used (`$$appState`). The first `$`-sign is used
|
|
72
|
-
to refer to the Component scope, as with any other state variable or computed property referenced in the template.
|
|
73
|
-
|
|
74
|
-
The second `$`-sign is needed, since the appState plugin itself is prefixed with a dollar sign, to prevent accidental naming collisions.
|
|
75
|
-
|
|
76
|
-
In order to read or update variables on the global app state inside the component logic, you can access the entire state via `this.$appState`.
|
|
77
|
-
|
|
78
|
-
### Watching global state
|
|
79
|
-
|
|
80
|
-
Similar to component state, you can watch for changes in the global state as well. You can refer to global state variables using _dot-notation_ in the watcher function name, and _prefixing_ it with `$appState`. This means that you need to define your watcher as a `String`, matching one of the examples below, depending on your style preference.
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
Blits.Component('MyComponent', {
|
|
84
|
-
template: `
|
|
85
|
-
<Element>
|
|
86
|
-
<Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
|
|
87
|
-
</Element>
|
|
88
|
-
`,
|
|
89
|
-
watch: {
|
|
90
|
-
'$appState.fooBar'(v, old) {
|
|
91
|
-
console.log(`$appState.fooBar changed from ${old} to ${v}`)
|
|
92
|
-
},
|
|
93
|
-
'$appState.my.nested.data': function(v, old) {
|
|
94
|
-
console.log(`My nested App state data changed!`)
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
})
|
|
98
|
-
```
|
|
1
|
+
# Global App State plugin
|
|
2
|
+
|
|
3
|
+
Each Blits Component has its own, internal component state that is reactive and can automatically trigger updates in the template upon changes. The internal state is fully encapsulated, which ensures predictable component state and promotes a pattern of clear separation of concerns.
|
|
4
|
+
|
|
5
|
+
But a Component usually doesn't live on its own, instead it's part of a bigger App. And there may arise a need for components to exchange data - intercomponent communication in other words.
|
|
6
|
+
|
|
7
|
+
Blits offers the option to _emit_ and _listen_ to events, as explained in the section on Blits [utility methods](../components/utility_methods.md). For simple use cases, this is a convenient method to pass data along. But when used extensively, it may be easy to lose track of data flows.
|
|
8
|
+
|
|
9
|
+
For more advanced cases, Blits offers an optional Global App State plugin that will act as a global state store that all components have direct access to. It's a simple implementation, focused on providing a _performant_ and _easy to use_ solution for global state. It's not a full flux / redux style state management solution, as we know from experience that these solutions (while very useful and cool), may lead to performance issues on low-end devices.
|
|
10
|
+
|
|
11
|
+
## Registering the plugin
|
|
12
|
+
|
|
13
|
+
The Global App state plugin is provided in the core Blits package, but as it's an _optional_ plugin it first needs to be registered.
|
|
14
|
+
|
|
15
|
+
The plugin can be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
|
|
16
|
+
|
|
17
|
+
Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method.
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// index.js
|
|
21
|
+
|
|
22
|
+
import Blits from '@lightningjs/blits'
|
|
23
|
+
// import the app state plugin
|
|
24
|
+
import { appState } from '@lightningjs/blits/plugins'
|
|
25
|
+
|
|
26
|
+
import App from './App.js'
|
|
27
|
+
|
|
28
|
+
// Use the Blits App State plugin
|
|
29
|
+
Blits.Plugin(appState, {
|
|
30
|
+
loggedIn: false,
|
|
31
|
+
user: {
|
|
32
|
+
id: null,
|
|
33
|
+
name: '',
|
|
34
|
+
lastname: ''
|
|
35
|
+
},
|
|
36
|
+
languages: ['en', 'nl', 'pt', 'es'],
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
Blits.Launch(App, 'app', {
|
|
41
|
+
// launch settings
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### State object
|
|
46
|
+
|
|
47
|
+
When registering the Global App State plugin, you pass it a state object as the second argument. This is a plain object literal that will be converted into a _reactive_ object, and is used to keep track of the global state variables.
|
|
48
|
+
|
|
49
|
+
The newly created Global App state works exactly the same as an internal Component state. You can read values and you can directly change values. And when you do change a value, it automatically triggers reactive updates. Either via reactive attributes in the template, or in the form of watchers / computed values in the Component logic.
|
|
50
|
+
|
|
51
|
+
### Using global app state in a Component
|
|
52
|
+
|
|
53
|
+
Any variable in the Global App state can be used directly in the template, much like a local Component state. Changing values in the global app state also works exactly the same as updating the internal component state.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
Blits.Component('MyComponent', {
|
|
57
|
+
template: `
|
|
58
|
+
<Element>
|
|
59
|
+
<Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
|
|
60
|
+
</Element>
|
|
61
|
+
`,
|
|
62
|
+
input: {
|
|
63
|
+
enter() {
|
|
64
|
+
this.$appState.user.name = 'John'
|
|
65
|
+
this.$appState.loggedIn = true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Note that in the template definition, 2 consecutive dollars signs are used (`$$appState`). The first `$`-sign is used
|
|
72
|
+
to refer to the Component scope, as with any other state variable or computed property referenced in the template.
|
|
73
|
+
|
|
74
|
+
The second `$`-sign is needed, since the appState plugin itself is prefixed with a dollar sign, to prevent accidental naming collisions.
|
|
75
|
+
|
|
76
|
+
In order to read or update variables on the global app state inside the component logic, you can access the entire state via `this.$appState`.
|
|
77
|
+
|
|
78
|
+
### Watching global state
|
|
79
|
+
|
|
80
|
+
Similar to component state, you can watch for changes in the global state as well. You can refer to global state variables using _dot-notation_ in the watcher function name, and _prefixing_ it with `$appState`. This means that you need to define your watcher as a `String`, matching one of the examples below, depending on your style preference.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
Blits.Component('MyComponent', {
|
|
84
|
+
template: `
|
|
85
|
+
<Element>
|
|
86
|
+
<Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
|
|
87
|
+
</Element>
|
|
88
|
+
`,
|
|
89
|
+
watch: {
|
|
90
|
+
'$appState.fooBar'(v, old) {
|
|
91
|
+
console.log(`$appState.fooBar changed from ${old} to ${v}`)
|
|
92
|
+
},
|
|
93
|
+
'$appState.my.nested.data': function(v, old) {
|
|
94
|
+
console.log(`My nested App state data changed!`)
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
```
|