Mojang / ore-ui

💎 Building blocks to construct game UIs using web tech.
https://react-facet.mojang.com/
MIT License
404 stars 19 forks source link

How should one use Map with a SharedFacet? #135

Closed rivendare closed 7 months ago

rivendare commented 7 months ago

e.g., in this example:

import { Map, useFacetState } from "@react-facet/core";
import { sharedFacet, sharedDynamicSelector, useSharedFacet } from "@react-facet/shared-facet";

interface Member {
    name: string
    rank: number
    health: number
}

const membersArray = [
    {
        name: "Zeus",
        rank: 3,
        health: 90
    },
    {
        name: "Demeter",
        rank: 2,
        health: 100
    },
    {
        name: "Poseidon",
        rank: 1,
        health: 85
    }
];

const membersFacet = sharedFacet<Member[]>("data.team", membersArray);

const memberNameSelector = sharedDynamicSelector((index: number) => [
    (member) => member[index].name,
    [membersFacet]
]);

const memberRankSelector = sharedDynamicSelector((index: number) => [
    (member) => member[index].rank,
    [membersFacet]
]);

const memberHealthSelector = sharedDynamicSelector((index: number) => [
    (member) => member[index].health,
    [membersFacet]
]);

const Member = ({ index }: { index: number }) => {
    return (
        <span>
            <b>Name: </b><fast-text text={useSharedFacet(memberNameSelector(index))}/>
            <br/>
            <b>Rank: </b><fast-text text={useSharedFacet(memberRankSelector(index))}/>
            <br/>
            <b>HP: </b><fast-text text={useSharedFacet(memberHealthSelector(index))}/>
            <br/>
            <hr/>
        </span>
    );
};

export const Team = () => {
    // works (as expected)
    // const [membersFacetState] = useFacetState<Member[]>(membersArray);

    // does not
    const membersFacetState = useFacetState(membersFacet);

    return (
        <Map array={membersFacetState}>
            {(_, index) => <Member index={index} />}
        </Map>
    );
};

the type error returned on Map's "array" prop:

TS2322: Type
[Facet<SharedFacet<Member[]>>, Setter<SharedFacet<Member[]>>]
is not assignable to type Facet<unknown[]>
Map.d.ts(4, 5): The expected type comes from property array which is declared here on type IntrinsicAttributes & MapProps<unknown>

I've tried digging through the docs, attempting to map from a SharedFacet to a Facet (couldn't seem to get that working), so figured I'd ask here. Thanks!

rivendare commented 7 months ago

ignore! feelin' silly now in hindsight, but got it working-- marking this issue as Closed

in case anyone else bumps into similar in the future, my solution:

import { Map } from "@react-facet/core";
import { sharedFacet, sharedDynamicSelector, useSharedFacet, sharedSelector } from "@react-facet/shared-facet";

interface Member {
    name: string
    rank: number
    health: number
}

interface TeamFacet {
    members: Member[]
}

const membersArray: Member[] = [
    {
        name: "Zeus",
        rank: 3,
        health: 90
    },
    {
        name: "Demeter",
        rank: 2,
        health: 100
    },
    {
        name: "Poseidon",
        rank: 1,
        health: 85
    }
];

const teamFacet = sharedFacet<TeamFacet>("data.team", {
    members: membersArray
});

const membersSelector = sharedSelector(({ members }) => members, [teamFacet]);

const memberNameSelector = sharedDynamicSelector((index: number) => [
    (members) => members[index].name,
    [membersSelector]
]);

const memberRankSelector = sharedDynamicSelector((index: number) => [
    (members) => members[index].rank,
    [membersSelector]
]);

const memberHealthSelector = sharedDynamicSelector((index: number) => [
    (members) => members[index].health,
    [membersSelector]
]);

const Member = ({ index }: { index: number }) => {
    return (
        <span>
            <b>Name: </b><fast-text text={useSharedFacet(memberNameSelector(index))}/>
            <br/>
            <b>Rank: </b><fast-text text={useSharedFacet(memberRankSelector(index))}/>
            <br/>
            <b>HP: </b><fast-text text={useSharedFacet(memberHealthSelector(index))}/>
            <br/>
            <hr/>
        </span>
    );
};

export const Team = () => {
    const members = useSharedFacet(membersSelector);

    return (
        <Map array={members}>
            {(_, index) => <Member index={index} />}
        </Map>
    );
};