Skip to content
This repository was archived by the owner on Feb 15, 2025. It is now read-only.

Commit 40f07ed

Browse files
committed
added basic useProxy docs
1 parent 1af15c5 commit 40f07ed

File tree

7 files changed

+255
-24
lines changed

7 files changed

+255
-24
lines changed

docs/Interfaces.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,3 +1118,156 @@ MY_COMPUTED.deps; // // Returns '[Observer(MY_LOCATION)]'
11181118
| Type | Default | Required |
11191119
|--------------------------|-----------|----------|
11201120
| `boolean` | true | No |
1121+
1122+
1123+
1124+
<br/>
1125+
1126+
---
1127+
1128+
<br/>
1129+
1130+
1131+
1132+
## `AgileHookConfigInterface`
1133+
1134+
The `AgileHookConfigInterface` is used as configuration object in functions like [`useAgile()`](./packages/react/features/Hooks.md#useagile).
1135+
Here is a Typescript Interface for quick reference. However,
1136+
each property is explained in more detail below.
1137+
```ts
1138+
interface AgileHookConfigInterface {
1139+
key?: SubscriptionContainerKeyType;
1140+
agileInstance?: Agile;
1141+
proxyBased?: boolean;
1142+
}
1143+
```
1144+
1145+
<br/>
1146+
1147+
#### `key`
1148+
1149+
The `key/name` of the [SubscriptionContainer](./packages/core/features/integration/Introduction.md#-subscriptions) that is created and added to the Observers.
1150+
```ts
1151+
useAgile(MY_STATE, {key: 'jeff'});
1152+
```
1153+
Such key can be very useful during debug sessions
1154+
in order to analyse when which SubscriptionContainer triggered a rerender on the Component.
1155+
```ts
1156+
// Agile Debug: Registered Callback/Component based Subscription 'jeff', SubscriptionContainer('jeff')
1157+
// Agile Debug: Updated/Rerendered Subscriptions, [SubscriptionContainer('jeff'), ..]
1158+
// Agile Debug: Unregistered Callback/Component based Subscription 'jeff', SubscriptionContainer('jeff')
1159+
```
1160+
1161+
| Type | Default | Required |
1162+
|--------------------------|-----------|----------|
1163+
| `string \| number` | undefined | No |
1164+
1165+
<br/>
1166+
1167+
#### `agileInstance`
1168+
1169+
The [Agile Instance](./packages/core/features/agile-instance/Introduction.md) the created [SubscriptionContainer](./packages/core/features/integration/Introduction.md#-subscriptions) belongs to.
1170+
However, since each Observer has an instance to the Agile Instance, `useAgile()` can automatically derive the Agile Instance from that.
1171+
1172+
| Type | Default | Required |
1173+
|---------------------------------------------------------------------------------|-----------|----------|
1174+
| [Agile Instance](./packages/core/features/agile-instance/Introduction.md) | undefined | No |
1175+
1176+
<br/>
1177+
1178+
#### `proxyBased`
1179+
1180+
If the `useAgile()` hook should wrap a [Proxy()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) around its return value/s.
1181+
Through this Proxy, AgileTs is able to track accessed properties in the returned object/s
1182+
and can construct a path to these.
1183+
The paths allow AgileTs to rerender the Component more efficiently,
1184+
by only causing a rerender when an actual accessed property value mutates.
1185+
Normally, the Component is always rerendered on a State change,
1186+
regardless of whether the property value is accessed in the Component.
1187+
This is totally fine if the value is primitive, or the whole object is displayed.
1188+
However, as soon as we display only a small part of the bound State value object,
1189+
the proxy feature might improve the performance.
1190+
```ts
1191+
const MY_STATE = App.createState({name: 'frank', age: 10})
1192+
1193+
// -- MyComponent.js ----------------------------------------
1194+
1195+
// Bind State to 'MyComponent.js'
1196+
const myState = useAgile(MY_STATE, {proxyBased: true});
1197+
1198+
return <p>{myState.name}</p>
1199+
1200+
// -- core.js ----------------------------------------------
1201+
1202+
// Cause rerender on 'MyComponent.js',
1203+
// since the .name property got accessed
1204+
MY_STATE.patch({name: 'jeff'});
1205+
1206+
// Doesn't cause rerender on 'MyComponent.js',
1207+
// since the .age property didn't got accessed
1208+
MY_STATE.patch({age: 20});
1209+
```
1210+
To avoid having to set the `proxyBased` configuration to `true` every time we use the proxy functionality,
1211+
we can use the [`useProxy()`](./packages/react/features/Hooks.md#useproxy) hook which does that part for us.
1212+
```ts
1213+
useProxy(MY_STATE);
1214+
// equal to
1215+
useAgile(MY_STATE, {proxyBased: true});
1216+
```
1217+
1218+
| Type | Default | Required |
1219+
|--------------------------|-----------|----------|
1220+
| `string \| number` | undefined | No |
1221+
1222+
1223+
1224+
<br/>
1225+
1226+
---
1227+
1228+
<br/>
1229+
1230+
1231+
1232+
## `ProxyHookConfigInterface`
1233+
1234+
The `ProxyHookConfigInterface` is used as configuration object in functions like [`useProxy()`](./packages/react/features/Hooks.md#useproxy).
1235+
Here is a Typescript Interface for quick reference. However,
1236+
each property is explained in more detail below.
1237+
```ts
1238+
interface ProxyHookConfigInterface {
1239+
key?: SubscriptionContainerKeyType;
1240+
agileInstance?: Agile;
1241+
}
1242+
```
1243+
1244+
<br/>
1245+
1246+
#### `key`
1247+
1248+
The `key/name` of the [SubscriptionContainer](./packages/core/features/integration/Introduction.md#-subscriptions) that is created and added to the Observers.
1249+
```ts
1250+
useProxy(MY_STATE, {key: 'jeff'});
1251+
```
1252+
Such key can be very useful during debug sessions
1253+
in order to analyse when which SubscriptionContainer triggered a rerender on the Component.
1254+
```ts
1255+
// Agile Debug: Registered Callback/Component based Subscription 'jeff', SubscriptionContainer('jeff')
1256+
// Agile Debug: Updated/Rerendered Subscriptions, [SubscriptionContainer('jeff'), ..]
1257+
// Agile Debug: Unregistered Callback/Component based Subscription 'jeff', SubscriptionContainer('jeff')
1258+
```
1259+
1260+
| Type | Default | Required |
1261+
|--------------------------|-----------|----------|
1262+
| `string \| number` | undefined | No |
1263+
1264+
<br/>
1265+
1266+
#### `agileInstance`
1267+
1268+
The [Agile Instance](./packages/core/features/agile-instance/Introduction.md) the created [SubscriptionContainer](./packages/core/features/integration/Introduction.md#-subscriptions) belongs to.
1269+
However, since each Observer has an instance to the Agile Instance, `useProxy()` can automatically derive the Agile Instance from that.
1270+
1271+
| Type | Default | Required |
1272+
|---------------------------------------------------------------------------------|-----------|----------|
1273+
| [Agile Instance](./packages/core/features/agile-instance/Introduction.md) | undefined | No |

docs/examples/react/Introduction.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ slug: /examples/react
1515

1616
## 👾 Performance
1717
- [Large State](./react/large-state)
18+
- [Frequent Updates](./react/frequent-updates)
1819

1920
You can get an overview of all performance examples in [this](https://github.com/agile-ts/performance-compare) repo.
2021

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
id: frequent-updates
3+
title: Frequent Updates
4+
sidebar_label: Frequent Updates
5+
slug: /examples/react/frequent-updates
6+
---
7+
8+
import {CodeSandBoxEmbed} from "../../../../src/components/docs/CodeSandBoxEmbed";
9+
10+
<CodeSandBoxEmbed uri={'agilets-frequent-updates-5tprm'} />
11+
12+

docs/main/Introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const App = new Agile();
9090
const MY_FIRST_STATE = App.createState("Hello Friend!");
9191

9292

93-
// -- myComponent.whatever ------------------------------------------
93+
// -- MyComponent.js ------------------------------------------
9494

9595
// 3️⃣ Bind initialized State to desired UI-Component
9696
// And wolla, it's reactive. Everytime the State mutates the Component rerenders

docs/packages/react/Introduction.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Therefore, we have created alternatives for Class Components in order to offer t
3636
In Functional Components we recommend using AgileTs Hooks like [`useAgile()`](./features/Hooks.md#useagile).
3737
The `useAgile()` Hook binds [Agile Sub Instances](../../main/Introduction.md#agile-sub-instance) (like States or Collections) to React Components.
3838
```ts
39-
// -- myComponent.jsx ------------------------------------------
39+
// -- MyComponent.jsx ------------------------------------------
4040

4141
// Binds MY_FIRST_STATE to myComponent
4242
const myFirstState = useAgile(MY_FIRST_STATE);
@@ -50,7 +50,7 @@ For Class Components, we provide the `AgileHOC`.
5050
The `AgileHOC` is a Higher Order Component that is wrapped around a React Component.
5151
It takes care of binding [Agile Sub Instances](../../main/Introduction.md#agile-sub-instance) (like States or Collections) to the wrapped React Component.
5252
```ts
53-
// -- myComponent.jsx ------------------------------------------
53+
// -- MyComponent.jsx ------------------------------------------
5454

5555
// Binds MY_FIRST_STATE to myComponent
5656
export default AgileHOC(myComponent, [MY_FIRST_STATE]);
@@ -63,4 +63,4 @@ checkout the [AgileHOC documentation](./features/AgileHoc.md).
6363
- [React Hook](./features/Hooks.md)
6464
- [useAgile](./features/Hooks.md#useagile)
6565
- [useWatcher](./features/Hooks.md#usewatcher)
66-
- [AgileHOC](./features/AgileHoc.md)
66+
- [AgileHOC](./features/AgileHoc.md)

docs/packages/react/features/Hooks.md

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ and not the State Instance itself.
2525
```ts {5}
2626
const MY_STATE = App.createState('jeff');
2727

28-
// myComponent.jsx
28+
// MyComponent.jsx
2929

3030
const myState = useAgile(MY_STATE);
3131
console.log(myState); // Returns 'jeff'
@@ -41,7 +41,7 @@ In which case it returns an array of State `values` that can be destructured.
4141
const MY_STATE = App.createState('jeff');
4242
const MY_STATE_2 = App.createState('frank');
4343

44-
// myComponent.jsx
44+
// MyComponent.jsx
4545

4646
const [myState, myState2] = useAgile([MY_STATE, MY_STATE_2]);
4747
console.log(myState); // Returns 'jeff'
@@ -66,7 +66,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
6666
```ts {5}
6767
const MY_STATE = App.createState('jeff');
6868

69-
// myComponent.jsx
69+
// MyComponent.jsx
7070

7171
const myState = useAgile(MY_STATE);
7272
console.log(myState); // Returns 'jeff'
@@ -75,7 +75,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
7575
```ts {5}
7676
const MY_COMPUTED = App.createComputed(() => 'hello there');
7777

78-
// myComponent.jsx
78+
// MyComponent.jsx
7979

8080
const myComputed = useAgile(MY_COMPUTED);
8181
console.log(myComputed); // Returns 'hello there'
@@ -90,7 +90,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
9090
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
9191
});
9292

93-
// myComponent.jsx
93+
// MyComponent.jsx
9494

9595
const myCollection = useAgile(MY_COLLECTION);
9696
console.log(myCollection); // Returns (see below)
@@ -103,7 +103,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
103103
});
104104
const MY_GROUP = MY_COLLECTION.createGroup('myGroup', [3, 1]);
105105

106-
// myComponent.jsx
106+
// MyComponent.jsx
107107

108108
const myGroup = useAgile(MY_GROUP);
109109
console.log(myGroup); // Returns '[{id: 3, name: 'c'}, {id: 1, name: 'a'}]'
@@ -115,7 +115,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
115115
});
116116
const MY_SELECTOR = MY_COLLECTION.select(2);
117117

118-
// myComponent.jsx
118+
// MyComponent.jsx
119119

120120
const mySelector = useAgile(MY_SELECTOR);
121121
console.log(mySelector); // Returns '{id: 2, name: 'b'}'
@@ -127,7 +127,7 @@ Instances that can be bound to a React Component via the `useAgile()` Hook:
127127
});
128128
const MY_ITEM = MY_COLLECTION.getItem(3);
129129

130-
// myComponent.jsx
130+
// MyComponent.jsx
131131

132132
const myItem = useAgile(MY_ITEM);
133133
console.log(myItem); // Returns '{id: 3, name: 'c'}'
@@ -186,7 +186,7 @@ type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
186186
```ts {5}
187187
const MY_STATE = App.createState('jeff');
188188

189-
// myComponent.jsx
189+
// MyComponent.jsx
190190

191191
const myState = useAgile(MY_STATE);
192192
console.log(myState); // Returns 'jeff'
@@ -196,7 +196,7 @@ When passing multiple Agile Sub Instances, an array of `outputs` matching the pa
196196
const MY_STATE = App.createState('jeff');
197197
const MY_STATE_2 = App.createState('frank');
198198

199-
// myComponent.jsx
199+
// MyComponent.jsx
200200

201201
const [myState, myState2] = useAgile([MY_STATE, MY_STATE_2]);
202202
console.log(myState); // Returns 'jeff'
@@ -215,15 +215,45 @@ console.log(myState2); // Returns 'frank'
215215

216216
## `useProxy()`
217217

218-
Basically `useProxy()` does the same as [`useAgile()`](#useagile)
219-
but it differs in one key area.
220-
It wraps a proxy around its return value,
221-
which has no limitation for the end user, but it allows AgileTs to track the used properties.
222-
With this information it is possible to only rerender the Component,
223-
when a used property mutates. In `useAgile()` it rerenders the Component
224-
whenever anything in the State changes, no matter it is displayed or not.
225-
Be aware that this is only useful if you pass an array or object State
226-
because it wouldn't make sense to track any primitive value.
218+
Basically `useProxy()` does the same as [`useAgile()`](#useagile),
219+
however it differs in one key area.
220+
It wraps a [Proxy()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) around its return value/s.
221+
Through this Proxy, AgileTs is able to track accessed properties in the returned object/s
222+
and can construct a path to these.
223+
The paths allow AgileTs to rerender the Component more efficiently,
224+
by only causing a rerender when an actual accessed property value mutates.
225+
With `useAgile()`, the Component is always rerendered on a State change,
226+
regardless of whether the property value is accessed in the Component.
227+
This is totally fine if the value is primitive, or the whole object is displayed.
228+
However, as soon as we display only a small part of the bound State value object,
229+
the `useProxy()` hook might improve the performance.
230+
231+
### 🗂 Array
232+
`useProxy()` also supports **arrays** of State Instances.
233+
```ts
234+
const [myCoolState1, myCoolState2] = useAgile([MY_COOL_STATE1, MY_COOL_STATE2]);
235+
```
236+
In which case it returns an array of State `values` that can be destructured.
237+
```ts {6}
238+
const MY_STATE = App.createState({name: 'jeff', age: 10});
239+
const MY_STATE_2 = App.createState({size: 100, weight: 200});
240+
241+
// MyComponent.jsx
242+
243+
const [myState, myState2] = useProxy([MY_STATE, MY_STATE_2]);
244+
console.log(myState); // Returns '{name: 'jeff', age: 10}'
245+
console.log(myState2); // Returns '{size: 100, weight: 200}'
246+
```
247+
248+
### 🏷 Subscribable Instances
249+
We are not limited to States.
250+
We can bind any [Agile Sub Instance](../../../main/Introduction.md#agile-sub-instance) that owns
251+
an `Observer` to React Components.
252+
```ts
253+
const [myCollection, myGroup, myState] = useProxy([MY_COLLECTION, MY_GROUP, MY_STATE]);
254+
```
255+
However, the [Proxy()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) will only be wrapped
256+
around objects and arrays. The other instances are treated as in [useAgile()](#useagile).
227257

228258
### 🔴 Example
229259

@@ -268,6 +298,41 @@ render(<RandomComponent/>);
268298

269299
The `useProxy()` Hook is almost 100% typesafe.
270300

301+
### 📭 Props
302+
303+
| Prop | Type | Description | Required |
304+
| ----------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------|
305+
| `deps` | Array<SubscribableAgileInstancesType\> \| SubscribableAgileInstancesType | Agile Sub Instances that are bound to the Component in which the useAgile Hook is located | Yes |
306+
| `config` | [ProxyHookConfigInterface](../../../Interfaces.md#proxyhookconfiginterface) | Configuration | No |
307+
308+
#### SubscribableAgileInstancesType
309+
```ts
310+
type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
311+
```
312+
313+
### 📄 Return
314+
315+
`useProxy()` returns the current `output` of the passed [Agile Sub Instance](../../../main/Introduction.md#agile-sub-instance).
316+
```ts {5}
317+
const MY_STATE = App.createState({name: 'jeff', age: 10});
318+
319+
// MyComponent.jsx
320+
321+
const myState = useAgile(MY_STATE);
322+
console.log(myState); // Returns '{name: 'jeff', age: 10}'
323+
```
324+
When passing multiple Agile Sub Instances, an array of `outputs` matching the passed Instances is returned.
325+
```ts {6}
326+
const MY_STATE = App.createState({name: 'jeff', age: 10});
327+
const MY_STATE_2 = App.createState('frank');
328+
329+
// MyComponent.jsx
330+
331+
const [myState, myState2] = useAgile([MY_STATE, MY_STATE_2]);
332+
console.log(myState); // Returns '{name: 'jeff', age: 10}'
333+
console.log(myState2); // Returns 'frank'
334+
```
335+
271336

272337

273338
<br />

0 commit comments

Comments
 (0)