Shared Facets
Shared Facets are the way of communicating back and forth from backend. They are constructed using string
identifiers that the backend will use to populate the information in JavaScript.
Shared Facets are defined using the string identifier and an optional initial value. Note that since the type of the data stored in the facet cannot necessarily be deduced from the arguments, it's important to pass in the type of the facet data as a type argument:
ts
import {sharedFacet } from '@react-facet/shared-facet'export interfaceUserFacet {username : stringsignOut (): void}export constuserFacet =sharedFacet <UserFacet >('data.user', {username : 'Alex',signOut () {},})
Note that to fully benefit of the performance improvements given by the facet approach over the default React state approach, it is recommended that when setting the new state, you mutate the original object instead of passing down a new one.
#
SelectorsSelectors allow to narrow data from an upstream shared facet:
ts
import {sharedFacet ,sharedSelector } from '@react-facet/shared-facet'interfaceUserFacet {user : {name : stringlastname : string}}constprofileFacet =sharedFacet <UserFacet >('data.user', {user : {name : 'Jane',lastname : 'Doe',},})constuserNameFacet =sharedSelector (({user }) =>user .name , [profileFacet ])
The user name facet will only hold the user name as data and can be consumed like this:
tsx
import {useSharedFacet } from '@react-facet/shared-facet'constUserData = () => {// This will print Janereturn (<span ><fast-text text ={useSharedFacet (userNameFacet )} /></span >)}
To avoid re-renders, you can specify an equality check function, so that if the original facet updates but the value of the data returned by the selector remains the same, listeners to the new facet will not get triggered pointlessly:
ts
import {sharedFacet } from '@react-facet/shared-facet'interfaceUserFacet {user : {name : stringlastname : string}}constprofileFacet =sharedFacet <UserFacet >('data.user', {user : {name : 'Jane',lastname : 'Doe',},})import {sharedSelector } from '@react-facet/shared-facet'import {shallowObjectEqualityCheck } from '@react-facet/core'constequalityCheck =shallowObjectEqualityCheck ()constuserNameFacetWithEqualityCheck =sharedSelector (({user }) =>user .name ,[profileFacet ],//equalityCheck,)
#
Dynamic SelectorsDynamic Selectors creates a selector that returns a facet based on a parameter. The typical use case of this is an index for a particular element on a list.
ts
import {sharedFacet ,sharedDynamicSelector } from '@react-facet/shared-facet'interfaceMessagesFacet {messages :ReadonlyArray <{content : stringtimestamp : number}>}constchatFacet =sharedFacet <MessagesFacet >('data.messages', {messages : [{content : 'Hello',timestamp : 0 },{content : 'Are you free?',timestamp : 12 },],})constmessageContentSelector =sharedDynamicSelector ((index : number) => [({messages }) =>messages [index ].content ,[chatFacet ],])
The selector will return a facet that holds the content of the particular message:
tsx
constMessage = ({index }: {index : number }) => {// For index 0, this will be "Hello"return (<span ><fast-text text ={useSharedFacet (messageContentSelector (index ))} /></span >)}
As with the regular selector, you can specify an equality check function:
ts
import {sharedDynamicSelector } from '@react-facet/shared-facet'import {strictEqualityCheck } from '@react-facet/core'constmessageContentSelector =sharedDynamicSelector ((index : number) => [({messages }) =>messages [index ].content ,[chatFacet ],],strictEqualityCheck ,)
#
Implementing facets in the game engineTODO