Create stale data indicator with XState
Published on
The are few things as boring as not knowing the state of an application. Is this document saved or should I Ctrl+S? In this article I present the stale data indicator we display on our Turing machine visualizer when visualizer is not in sync with inputs.
This article is the fourth one of a series about our Turing machine visualizer built with XState .
This is the feature I’m the most proud of, while it was one of the simplest to implement. But it gives the visualizer a more professional look.
When input or machine configuration are different from the last input and machine configuration that led to a successful execution, we indicate that inputs are stale:
To implement this, first we need to cache the previous input and machine configuration when we receive a successful execution result:
ts
const vizMachine = createMachine({context: {// Other properties...input: "",machineCode: "",lastSuccessfullyExecutedInput: undefined,lastSuccessfullyExecutedMachineCode: undefined,},schema: {context: {} as {// Other properties...input: string;machineCode: string;lastSuccessfullyExecutedInput: string | undefined;lastSuccessfullyExecutedMachineCode: string | undefined;},},// ...type: "parallel",states: {// ..."Managing input and machine execution": {initial: "Idle",states: {"Idle": {},"Executing machine and input": {// ...type: "parallel",states: {"Making request to server": {initial: "Sending request",states: {"Sending request": {invoke: {src: "Execute machine and input on server",onDone: {actions: "Assign machine execution to context",target: "Received response",},onError: {target: "Error occured",},},},"Received response": {entry: "Cache input and machine code into context",type: "final",},"Error occured": { /** */ },},},"Delaying loading state": { /** */ },},onDone: [ /** */ ],},"Received response": { /** */ },"Failed to execute machine with input": { /** */ },},// ...},},// ...}, {actions: {"Cache input and machine code into context": assign({lastSuccessfullyExecutedInput: (context) => context.input,lastSuccessfullyExecutedMachineCode: (context) => context.machineCode,}),},});
Received response
state is entered when the server responds with a successful execution result. When this state is entered, we cache the input and machine code into the context.
We implemented the request to the server in a previous article.
Then in Vue side, we create a computed
property:
ts
import { computed } from 'vue';const isStale = computed(() => {const {input,lastSuccessfullyExecutedInput,machineCode,lastSuccessfullyExecutedMachineCode} = state.value.context;if (lastSuccessfullyExecutedInput === undefined ||lastSuccessfullyExecutedMachineCode === undefined) {return false;}return (input !== lastSuccessfullyExecutedInput ||machineCode !== lastSuccessfullyExecutedMachineCode);});
If no successful execution has been performed yet, cached values are undefined
, and data are not stale. Otherwise, we compare values with the cached ones and return true
if at least one of input
and machineCode
is different from its corresponding cached value.
If you are coming from React world, a computed property is like a useMemo
.
The computed property is then used to dynamically display the stale indicator (and apply a transition!):
svelte
<Transitionleave-active-class="duration-100 ease-in"leave-from-class="opacity-100"leave-to-class="opacity-0"><AppBadge v-if="isStale">Stale</AppBadge></Transition>
This is a stylistic detail, but it greatly improves the UX. Furthermore, it is not so hard to implement technically.
permalinkSummary
We saw that not every piece of logic has to be decided by XState. We picked values from machine context to compute some logic in Vue side. XState orchestrates, and view layer derives from XState.
So that’s the fourth article of the series about Turing machine visualizer showcase! The last article will be released soon.
We’ll talk about the Load button of the visualizer, and precisely about the way we animate it.
You can already try the load button by executing a machine.
The code of the visualizer is on GitHub.
The series contains the following articles:
- Control tape of Turing machine visualizer with XState
- Orchestrate request for server-side execution of Turing machine with XState
- Prevent flickering loading animation with XState
- Create stale data indicator with XState
- Create a proxy state machine to drive CSS transitions on state changes with XState