-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(state-query): add recs to new docs (#1917)
- Loading branch information
Showing
1 changed file
with
133 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,134 @@ | ||
# RECS | ||
|
||
The recs package is a way to query the [Store](/store/introduction) and react to changes. | ||
|
||
There are two APIs to read data and react to changes with `recs`: | ||
|
||
- [Reading component value directly](#reading-component-value-directly). | ||
- [Subscribing to a query that returns a set of matching entities](#running-queries). | ||
|
||
For the examples below, let's assume this MUD config. Notice that each of these tables has an (implicit) `bytes32` key. | ||
|
||
```typescript | ||
const config = mudConfig({ | ||
tables: { | ||
NameComponent: "string", | ||
PlayerComponent: "bool", | ||
PositionComponent: { valueSchema: { x: "int32", y: "int32" } }, | ||
}, | ||
}); | ||
``` | ||
|
||
## Reading component value directly | ||
|
||
If you have a specific key and a reference to a component, you can query its value directly, or use a React hook that will re-render when the corresponding component value updates. | ||
|
||
### Reading component value in vanilla javascript | ||
|
||
```typescript | ||
import { getComponentValueStrict } from "@latticexyz/recs"; | ||
// note: NameComponent is an recs component; components could come from the `setup` function of MUD. | ||
const { NameComponent } = components | ||
// get a reference to the recs world; as an example from the `setup` function of MUD. | ||
const world = [...] | ||
// you need a reference to an `Entity` from recs. For the sake of the example, let's say we know that the bytes32 key is "0xDEAD" | ||
// you wouldn't do normally: entities would be found via queries. | ||
const entityID = "0xDEAD" as EntityID; | ||
const entity = world.registerEntity({ id: "0xDEAD" as EntityI }) | ||
// now we can fetch the value of the NameComponent on our entity | ||
const name = getComponentValueStrict(NameComponent, entity) | ||
// -> "John Doe" | ||
``` | ||
|
||
### Reading component value in react with `@latticexyz/react` | ||
|
||
```tsx | ||
import { useComponentValue } from "@latticexyz/react"; | ||
function ExampleComponent() { | ||
const { components, world } = useMUD; | ||
const { NameComponent } = components; | ||
// you need a reference to an `Entity` from recs. For the sake of the example, let's say we know that the bytes32 key is "0xDEAD" | ||
// you wouldn't do this normally: entities would be found via queries. | ||
const entityID = "0xDEAD" as EntityID; | ||
const entity = world.registerEntity({ id: "0xDEAD" }); | ||
// now we can fetch the value of the NameComponent on our entity | ||
const name = useComponentValue(NameComponent, entity); | ||
// -> "John Doe" | ||
// this will re-render when the component value changes! | ||
return <p>{name ?? "<no name>"}</p>; | ||
} | ||
``` | ||
|
||
## Running queries | ||
|
||
A common way of working with ECS data is by using queries. | ||
A query is a function that returns a list of entities that match a set of predicates called _query fragments_. | ||
|
||
There are 4 types of query fragments: | ||
|
||
1. `Has`: matches entities that have a specific component. | ||
2. `Not`: matches entities that do not have a specific component. | ||
3. `HasValue`: matches entities that have a specific component with a set value. | ||
4. `NotValue`: matches entities that do not have a component with a set value (will also match if it doesn't have the component at all) | ||
|
||
### Running query with vanilla javascript | ||
|
||
```typescript | ||
import { runQuery, Has, HasValue, getComponentValueStrict } from "@latticexyz/recs"; | ||
const { PlayerComponent, PositionComponent, NameComponent } = components | ||
// query for all named players at the center of the universe | ||
const matchingEntities = runQuery([ | ||
Has(PlayerComponent), | ||
Has(Name), | ||
HasValue(PositionCompoennt, {x: 0, y: 0}) | ||
]) | ||
// now you can map these to their name as an example | ||
const names = matchingEntities.map( | ||
playerEntity => getComponentValueStrict(NameComponent, playerEntity | ||
) | ||
// -> ["Bob", "Alice", "Eve"] | ||
``` | ||
### Reacting to queries with vanilla javascript | ||
```typescript | ||
import { defineSystem, Has, HasValue, getComponentValueStrict, UpdateType } from "@latticexyz/recs"; | ||
const { PlayerComponent, PositionComponent, NameComponent } = components | ||
// get a reference to the recs world; as an example from the `setup` function of MUD. | ||
const world = [...] | ||
defineSystem(world, [Has(PlayerComponent), Has(Name), HasValue(PositionComponent, {x: 0, y: 0}], ({entity, component, value, type}) => { | ||
// every time an entity enter, exit, or get updated within a query; this callback with fire | ||
// the "type" will match these: UpdateType.Enter, UpdateType.Exit, UpdateType.Update | ||
// as an example, if a new entity is named, has a player component, and is at the center of the universe; the callback fires | ||
// if the name of a player at the center of the universe changes, the callback will also fire for that entity | ||
// let's only log when a new entity matches this query | ||
// every time a named player reaches {0, 0}; we want to log their name | ||
if(type !== UpdateType.Enter) return | ||
console.log(getComponentValueStrict(NameComponent, entity) + " reached the center!") | ||
}) | ||
``` | ||
### Reacting to queries with React and `@latticexyz/react` | ||
```tsx | ||
import { useEntityQuery } from "@latticexyz/react"; | ||
import { Has, HasValue, getComponentValueStrict } from "@latticexyz/recs"; | ||
function ExampleComponent() { | ||
const { components, world } = useMUD; | ||
const { NameComponent, PlayerComponent, PositionCompoennt } = components | ||
// get a list of all entities that are named, players, and at the center of the universe | ||
// it is reactive and will trigger a re-render when the set of matching queries update | ||
const entities = useEntityQuery([Has(PlayerComponent), Has(Name), HasValue(PositionComponent, {x: 0, y: 0}]) | ||
// [entity1, entity2, ...] | ||
return( | ||
<div> | ||
<span>Players at the center:</span> | ||
<ul> | ||
{entities.map(entity => ( | ||
<li>{getComponentValueStrict(NameComponent, entity)}</li> | ||
))} | ||
</ul> | ||
</div> | ||
) | ||
} | ||
``` |