Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add state transformer #218

Merged
merged 8 commits into from
Aug 18, 2024
Merged

Add state transformer #218

merged 8 commits into from
Aug 18, 2024

Conversation

GabrielCTroia
Copy link
Contributor

@GabrielCTroia GabrielCTroia commented Aug 18, 2024

What/Why

Sometimes the Master (server) State needs to change based on something else than a client Action dispatch, such as time, or an external event.

Normally, on an in-house server, this would be handled by CRON jobs or by other event listeners, but since Movex abstracts the server away and to keep things as simple as possible, I chose the idea of the state being transformed on read – enter the $transformState().

What this means, is that the state doesn't change unless it's read, which is when the stateTransformer gets involved.

What is a $stateTransformer

A state transformer is a simple function of following type, and can be attached to any MovexReducer.

$transformState?: (state: S, context: MovexMasterContext) => S;

It gets called every time the reducer runs, meaning on each Action Dispatch or on each MovexResource.get() or even via the Movex API.

If you notice it takes a secondary argument masterContext, that looks like this:

export type MovexMasterContext = {
  requestAt: number; // timestamp
};

The MovexMasterContext provides a way to access the context of the Movex Master (Server) while keeping things pure in the reducer.

Keep in mind that context.requestAt will always return a new timestamp per request, which means that the requestAt value changes only on new requests, but not if it's called multiple times during the same event by Movex internally, to ensure the accuracy of the transformed state just as in a pure function.

Example

// See libs/movex-specs-util/src/lib/resources/speedPushGame.ts

speedPushGameReducer.$transformState = (state: State, context) => {
  const NOW = context.requestAt;

  if (
    state.status === 'ongoing' &&
    NOW > state.lastPushAt + state.timeToNextPushMs
  ) {
    return {
      status: 'completed',
      winner: state.lastPushBy,
      lastPushAt: state.lastPushAt,
      lastPushBy: state.lastPushBy,
      timeToNextPushMs: state.timeToNextPushMs,
    };
  }

  return state;
};

In this example above, the logic checks wether enough time has passed since last action and change the status of the game state if so. Take a look at the full example here libs/movex-specs-util/src/lib/resources/speedPushGame.ts.

@GabrielCTroia GabrielCTroia merged commit 0756c57 into add-storybook Aug 18, 2024
@GabrielCTroia GabrielCTroia deleted the add-state-transformer branch August 18, 2024 14:47
@GabrielCTroia GabrielCTroia mentioned this pull request Sep 26, 2024
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant