Skip to content

Commit 2fa0ef3

Browse files
authored
Merge pull request #18 from meeees/main
Add doc with examples for useReactiveValue
2 parents d275ad9 + 57ed71e commit 2fa0ef3

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

src/content/learn/howto/interop.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ There are several ways to achieve interop in ReactUnity.
1414

1515
### `Globals` object
1616

17-
This method uses the `Globals` object to have two-way communication between React and C#. Also, `useGlobals` is a hook that is available in React side and it rerenders the component when `Globals` object changes.
17+
This method uses the `Globals` object to have two-way communication between React and C#. Also, `useGlobals` is a hook that is available in React side and it re-renders the component when `Globals` object changes.
1818

1919
API reference for `useGlobals` can be found [here](/reference/api/useglobals).
2020

21+
`useReactiveValue` is a further hook that can be used to re-render on individual property changes of a C# object, see [here](/reference/api/usereactivevalue).
22+
2123
### `Interop` namespace
2224

2325
`Interop` is a namespace in React side that can be used to call C# and Unity static functions from React side. It allows doing C# operations without going out of Javascript.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
title: useReactiveValue()
3+
layout: API
4+
---
5+
## Storing Primitives
6+
The `useReactiveValue` hook combined with the `ReactiveValue<T>` C# class allows you to hook into individual properties of an object.
7+
8+
`ReactiveValue`'s are set via the `.Value` property, which will automatically trigger any watching hooks.
9+
10+
For example, this `Player` `MonoBehaviour` could be stored in Globals:
11+
12+
```csharp
13+
// C#
14+
public class Player: MonoBehaviour {
15+
16+
public ReactRendererBase renderer;
17+
18+
// special class for communicating between React and Unity
19+
public ReactiveValue<float> Score = new ReactiveValue<float>();
20+
public ReactiveValue<int> Deaths = new ReactiveValue<int>();
21+
public ReactiveValue<int> Kills = new ReactiveValue<int>();
22+
23+
void Awake() {
24+
renderer.Globals["Player"] = this;
25+
}
26+
27+
// set ReactiveValue with .Value
28+
public void AddScore(float score) {
29+
Score.Value += score;
30+
}
31+
32+
/* Rest of Player code */
33+
}
34+
```
35+
And then accessed in React via the hook:
36+
```js
37+
// JS
38+
export function ScoreTracker() {
39+
const {Player} = useGlobals();
40+
// will trigger a re-render when Score changes
41+
const score = useReactiveValue(Player.Score);
42+
43+
return (<text>{score}</text>)
44+
}
45+
```
46+
47+
## Non-Primitive Types
48+
For Lists and Dictionaries, there are the `ReactiveList<T>` and `ReactiveRecord<T>` classes.
49+
50+
Normal `ReactiveValue`'s can also hold non-primitive objects, but they will only trigger a re-draw if the actual object reference changes.
51+
52+
It's recommended to either use a `ReactiveValue` per field (see above), an immutable type like `record`, or a secondary variable for tracking the state change (see below).
53+
54+
### Method 1: ReactiveList
55+
Say we want to store a Player's inventory for drawing on the UI. The simplest approach is to use a `ReactiveList`:
56+
```csharp
57+
// C#
58+
/* Player class continued */
59+
{
60+
// track a list of all items in the inventory
61+
public ReactiveList<Item> Inventory = new ReactiveList<Item>();
62+
63+
public void AddItem(Item item) {
64+
// will trigger re-renders as needed
65+
Inventory.Add(item);
66+
}
67+
}
68+
```
69+
```js
70+
// JS
71+
export function DrawItems() {
72+
const {Player} = useGlobals();
73+
const itemList = useReactiveValue(Player.Inventory);
74+
// return drawn items
75+
}
76+
```
77+
78+
### Method 2: Secondary Variable
79+
Now we want to add more functionality to the inventory, and it can no longer be just a list. Instead it is an `Inventory` object, and we track changes to its internal state with a counter variable.
80+
```csharp
81+
/* Player class continued */
82+
{
83+
public ReactiveValue<int> InventoryChanges = new ReactiveValue<int>();
84+
public InventorySystem Inventory;
85+
86+
public void AddItem(Item item) {
87+
// trigger re-render with counter instead
88+
InventoryChanges.Value += 1;
89+
Inventory.Add(item);
90+
}
91+
}
92+
```
93+
```js
94+
// JS
95+
export function DrawItems() {
96+
const {Player} = useGlobals();
97+
98+
// re-render based on the counter
99+
const _invChanges = useReactiveValue(Player.InventoryChanges);
100+
101+
// reference the Inventory object and call functions
102+
const inventory = Player.Inventory;
103+
const itemList = inventory.ListItems();
104+
105+
// call other functions from Inventory class
106+
107+
// return drawn items
108+
}
109+
```

src/sidebarReference.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
{
1919
"title": "useGlobals()",
2020
"path": "/reference/api/useglobals"
21+
},
22+
{
23+
"title": "useReactiveValue()",
24+
"path": "/reference/api/usereactivevalue"
2125
}
2226
]
2327
},

0 commit comments

Comments
 (0)