State Query
TypeScript
RECS

RECS

The recs package is a way to query the Store and react to changes.

There are two APIs to read data and react to changes with recs:

For the examples below, let's assume this MUD config. Notice that each of these tables has a bytes32 key.

const config = defineWorld({
  namespace: "app",
  tables: {
    NameComponent: {
       schema: {
         value: "string",
         id: "bytes32"
       },
       key: ["id"],
    }
    PlayerComponent: {
       schema: {
         value: "bool",
         id: "bytes32",
       },
       key: ["id"],
    },
    PositionComponent: {
       schema: {
         x: "int32",
         y: "int32",
         id: "bytes32",
       },
       key: ["id"],
    },
  },
});

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

import { getComponentValueStrict } from "@latticexyz/recs";
// note: NameComponent is a recs component; components could come from the `setup` function of MUD.
const { NameComponent } = components
// get a reference to the world; as an example from the `setup` function of MUD.
const world = [...]
// you need a reference to an `Entity`. 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

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

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

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

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>
  )
}