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

Batching support #122

Closed pirelenito closed 1 year ago

pirelenito commented 1 year ago

The main motivation is to prevent execution of effects with "transient" values. The pseudo-code below explains in a better way a very common scenario when working with Facets:

type User = { name: string; login: string }

// Starting with a single Facet
const [user, setUser] = useFacetState<User>({ name: 'Initial Name', login: 'Initial Login' })

// We might map it into more specific properties
const nameFacet = useFacetMap(({ name }) => name, [], [user])
const loginFacet = useFacetMap(({ login }) => login, [], [user])

// But latter, we could have an effect that depends on both values
useFacetEffect(
  (name, login) => {
    // Before batching, this effect would be called twice
    // - First time: with name containing the new value, but login with old
    // - Second time : with both name and login containing their new values
  },
  [],
  [nameFacet, loginFacet],
)

Batching by default

It changes the default implementation of createFacet to automatically start a batch when its updated, so consumers will get the benefit of batching without having to update any of their code.

Batching multiple Facets

In addition, it does introduce a new API batch, that allows batching together multiple Facet updates.

batch(() => {
  facetA.set('new value')
  facetB.set('something else')
})

This API was inspired by existing community patterns, such as Solid's batch.

Performance

Benchmarks done in the internal Mojang codebase showed either an improvement or similar performance after this change (backed by the benchmarks in this repository).

Release candidates

To try this out, we've been publishing RCs at https://github.com/Mojang/ore-ui/compare/batch...batch-rc