📖 Scenario: You are building a simple traffic light controller using Vue 3. The traffic light changes colors in a fixed order: green, then yellow, then red, and back to green. You want to manage these states clearly and predictably using a state machine pattern with Vue composables.
🎯 Goal: Create a Vue 3 composable that manages the traffic light states as a state machine. Then use this composable in a component to display the current light color and a button to move to the next state.
📋 What You'll Learn
Create a composable function called useTrafficLight that manages the traffic light states.
Define the states: green, yellow, and red.
Add a function next inside the composable to move to the next state in order.
Create a Vue component that uses useTrafficLight to show the current state and a button to trigger next.
💡 Why This Matters
🌍 Real World
State machines are used in real-world apps to manage complex states clearly, such as UI workflows, game states, or device controls.
💼 Career
Understanding state machines and composables is valuable for frontend developers working with Vue to build maintainable and predictable user interfaces.
Progress0 / 4 steps
1
Set up the traffic light states
Create a composable function called useTrafficLight that returns a reactive variable state initialized to the string 'green'.
Vue
Hint
Use ref from Vue to create a reactive state variable inside the composable.
2
Add the state order configuration
Inside useTrafficLight, create a constant array called states with the values 'green', 'yellow', and 'red' in that order.
Vue
Hint
Use a simple array to list the states in the order they should cycle.
3
Implement the next state function
Inside useTrafficLight, add a function called next that updates state.value to the next state in the states array, cycling back to 'green' after 'red'. Return next from the composable.
Vue
Hint
Find the current state's index, add one, and use modulo to cycle back to zero.
4
Create the Vue component using the composable
Create a Vue component with <script setup> that imports useTrafficLight, calls it to get state and next, and in the template shows the current state and a button labeled Next that calls next on click.
Vue
Hint
Use @click on the button to call next. Display state inside the template.
Practice
(1/5)
1. What is the main purpose of using a state machine in a Vue composable?
easy
A. To manage and control the different states of an application clearly and predictably
B. To style components dynamically based on user input
C. To fetch data from an API asynchronously
D. To create reusable UI components without state
Solution
Step 1: Understand state machine role
A state machine helps track and control states in a clear way, avoiding unpredictable behavior.
Step 2: Relate to Vue composables
Vue composables organize this logic so it can be reused across components easily.
Final Answer:
To manage and control the different states of an application clearly and predictably -> Option A
Quick Check:
State machine purpose = Manage states clearly [OK]
Hint: State machines organize app states clearly, not styling or fetching [OK]
Common Mistakes:
Confusing state machines with styling or data fetching
Thinking composables only create UI components
Assuming state machines handle API calls
2. Which of the following is the correct way to declare a reactive state variable for a state machine in a Vue composable?
easy
A. const state = reactive('idle')
B. const state = ref('idle')
C. const state = computed('idle')
D. const state = watch('idle')
Solution
Step 1: Identify reactive state declaration
In Vue composables, ref is used to create a reactive primitive value like a string.
Step 2: Check other options
reactive is for objects, computed is for derived values, and watch is for side effects, so they are incorrect here.
Final Answer:
const state = ref('idle') -> Option B
Quick Check:
Use ref for reactive primitives [OK]
Hint: Use ref() for reactive simple values like strings [OK]
Common Mistakes:
Using reactive() for primitive values
Confusing computed() with state declaration
Using watch() to declare state
3. Given this Vue composable code, what will be the value of state.value after calling next() twice?
import { ref } from 'vue'
export function useMachine() {
const state = ref('idle')
function next() {
if (state.value === 'idle') state.value = 'loading'
else if (state.value === 'loading') state.value = 'success'
}
return { state, next }
}
medium
A. 'idle'
B. 'loading'
C. 'success'
D. undefined
Solution
Step 1: Trace first next() call
Initial state is 'idle'. Calling next() changes it to 'loading'.
Step 2: Trace second next() call
Now state is 'loading'. Calling next() again changes it to 'success'.
Final Answer:
'success' -> Option C
Quick Check:
Two next() calls move state from idle -> loading -> success [OK]
Hint: Trace state changes step-by-step for each next() call [OK]
Common Mistakes:
Assuming state resets to 'idle'
Forgetting second next() changes state again
Confusing state.value with state itself
4. Identify the error in this Vue composable state machine code:
import { ref } from 'vue'
export function useMachine() {
const state = ref('idle')
function next() {
if (state === 'idle') state.value = 'loading'
else if (state.value === 'loading') state.value = 'success'
}
return { state, next }
}
medium
A. next() function is not returned
B. Missing import of ref from 'vue'
C. Cannot assign to state.value, should assign to state
D. Incorrect comparison: should use state.value instead of state
Solution
Step 1: Check state comparisons
state is a ref object, so to compare its value, use state.value, not state directly.
Step 2: Verify other parts
Import is correct, assignment to state.value is correct, and next() is returned properly.
Final Answer:
Incorrect comparison: should use state.value instead of state -> Option D
Quick Check:
Compare ref values with state.value [OK]
Hint: Always compare ref values with .value, not the ref object [OK]
Common Mistakes:
Comparing ref object instead of its value
Forgetting to return functions from composable
Misassigning to ref object instead of .value
5. You want to extend a Vue composable state machine to handle a 'failure' state after 'loading'. Which change correctly adds this new state transition when next() is called from 'loading'?
hard
A. Add an else if: else if (state.value === 'loading') state.value = 'failure'
B. Replace the existing loading transition with state.value = 'failure' only
C. Add a new function to set state to 'failure' instead of modifying next()
D. Change initial state to 'failure' to handle errors
Solution
Step 1: Understand current transitions
Currently, next() changes 'idle' -> 'loading' -> 'success'. To handle 'failure' after 'loading' when next() is called, add a new else if condition for 'loading' to transition to 'failure'.
Step 2: Identify correct addition
Adding an else if for state.value === 'loading' to set state.value = 'failure' extends the state machine correctly without removing existing transitions.
Final Answer:
Add an else if: else if (state.value === 'loading') state.value = 'failure' -> Option A
Quick Check:
Add new transition for loading -> failure without removing others [OK]
Hint: Add a new else if condition for the failure state [OK]
Common Mistakes:
Adding a duplicate else if for 'loading' which conflicts or is unreachable
Adding separate functions instead of modifying next()
Changing initial state instead of the transition
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.