State
Volver a la referencia

State

The state an object keeps while it lives, and code that runs when it changes.

5 símbolos

useDatafunctionhooknacatamalon

useData(initial: T) => [TDataRecord<T>, TDataSetter<T>]

State that lives with a piece of the scene, as [data, setData].

Read it as data.value, change it with the setter, and have something react to it with useWatch(fn, [data]). Two things far apart can share one: whoever makes it can hand it to whatever it builds, and each of them watches it without knowing about the others.

Change it through the setter, not with data.value = x. Writing to the field works and is read back correctly, but nothing is told about it, so a useWatch on it will not run.

It is also what gets saved. A scene written down carries this state and gives it back when the scene is opened again, which is what makes a saved game a saved game and not a fresh start. Keep in it the kind of thing a file can hold: numbers, text, lists and plain objects. A texture or a function is not something a file can keep.

Call it in the scene body, like the rest of the hooks.

Parámetros

initialT

What it holds before anything changes it.

Ejemplo

declare const counter: TText;

export const Level: TSceneFn = () => {
    const [lives, setLives] = useData(3);

    useWatch(() => {
        counter.text = `LIVES ${lives.value}`;
    }, [lives]);

    usePointer().onDown(() => setLives((n) => n - 1));

    return createScene();
};
Ver el código · hooks/state/use_data.ts:81

useWatchfunctionhooknacatamalon

useWatch(fn: () => void, deps: typeOperator) => void

Runs your code on the first frame, and again whenever one of the things you listed changes.

What goes in the list is the thing itself ([lives, texture]), not a reading of it: those objects are changed in place and never swap identity, so there would be nothing to compare. The engine keeps a count of how many times it has announced a change on each one, and this compares those counts once a frame.

The other side of that: a change the engine was not told about does not count. setLives(2) is announced and lives.value = 2 is not, exactly like React's rule about not assigning to state. Anything a game moves by hand, a transform above all, is changed in place all the time and is never announced, so it cannot be watched. Passing one is refused when the scene starts rather than accepted into a callback that would never run again.

The first run happens whether or not anything changed, so a scene does not need to write its starting state twice: once in the body and once in the watch.

It runs in the same pass as useUpdate and in the order written, so a scene in pause does not watch, the same way it does not update. A change made while it was paused is seen on the first frame after it resumes. If something has to be heard even in pause, that is what useStore and useSignal are for.

Two changes to the same thing in one frame are one run: what is compared is where things ended up, once a frame, not every step they took.

Parámetros

fn() => void

What to run. It takes nothing: read the things you listed.

depstypeOperator

What to watch. Changing what is in this list later has no effect: it is read once.

Ejemplo

declare const counter: TText;
declare const hero: TSprite;

export const Level: TSceneFn = () => {
    const texture = useLoadTexture({ src: '/assets/hero.png' });
    const [lives, setLives] = useData(3);

    useWatch(() => {
        counter.text = `LIVES ${lives.value}`;
        hero.visible = texture.status === 'ready';
    }, [lives, texture]);

    return createScene();
};
Ver el código · hooks/state/use_watch.ts:66

TDataRecordtypenacatamalon

State that belongs to one piece of the scene, handed back as an object you read .value from.

An object and not the value itself, because the body of a scene runs once: a plain value read there would be the value it had at that moment, for ever, no matter what happened afterwards. The object never changes identity, so reading .value later, inside useUpdate or a click, always gives what it holds now.

Propiedades

valueT
Ver el código · hooks/state/use_data.ts:15

TDataSettertypenacatamalon

TDataSetter: (next: T | (previous: T) => T | void) => void

How that state is changed. Three forms, and they are interchangeable:

  • the next value: setLives(2);
  • a function that returns the next value: setLives((n) => n - 1);
  • a function that changes it in place and returns nothing: setHero((h) => { h.x += 1; }).

The third is why the function may return nothing: when it does, what it was given is taken as already changed. That is the same shape a store's set has, so one habit covers both, while the returning form stays there for numbers and strings, where changing in place is not possible.

Whichever form is used, the change is announced, which is what useWatch is listening for.

Ver el código · hooks/state/use_data.ts:36

TWatchDeptypenacatamalon

TWatchDep: object

Something useWatch can be given to watch: state from useData, or an asset from one of the useLoad… hooks.

Not a number or a string. Those are read once, where the list is written, and can never change afterwards, so watching one is always a mistake and is refused rather than accepted quietly.

Ver el código · hooks/state/use_watch.ts:14