Welcome to Chapter 3! In the previous chapter, Fast Mode Business Logic, we wrote the code to toggle "Fast Mode" on and off. We calculated whether the user was allowed to use it and we saved their preference to a file.
However, we have a missing link.
When you run fast on, how does the rest of the applicationβlike the UI that shows the current model name, or the AI loop that sends messagesβknow that the setting has changed?
This brings us to the Global Application State.
Imagine you are in a classroom.
In the fast project, the Global Application State is that whiteboard. It is the "Single Source of Truth."
We need to build the FastModePicker (a menu that lets users toggle the mode).
We interact with this "Whiteboard" using two special tools (Hooks):
useAppState)This hook allows a component to "put on glasses" and look at a specific part of the whiteboard. If that part of the whiteboard changes, the component automatically re-runs to show the new data.
useSetAppState)This hook gives you a "marker." It allows you to change what is written on the whiteboard.
AppState)This is the data structure itself. It looks something like this:
type AppState = {
mainLoopModel: string; // e.g., 'claude-3-opus'
fastMode: boolean; // e.g., true or false
// ... other global settings
}
Let's see how we use these tools inside our FastModePicker component (found in fast.tsx).
We want to know the current model and whether fast mode is active.
import { useAppState } from '../../state/AppState.js';
// Inside a React Component:
const model = useAppState(state => state.mainLoopModel);
const isFastMode = useAppState(state => state.fastMode);
Explanation:
useAppState takes a "selector function."state => state.fastMode means: "I only care about the fastMode variable. Please give me its current value."fastMode changes from false to true, this component will re-render automatically.Now, let's look at how we update the state when the user toggles the feature.
import { useSetAppState } from '../../state/AppState.js';
// 1. Get the "marker" (the setter function)
const setAppState = useSetAppState();
// 2. Use it to update state
setAppState(currentState => ({
...currentState, // Keep all other settings the same!
fastMode: true // Overwrite this specific setting
}));
Explanation:
setAppState is a function that accepts an update function....currentState: This is the "Spread Operator." It copies everything currently on the whiteboard so we don't accidentally erase the user's other settings.fastMode: true: We explicitly change only the value we want.
When you call setAppState, a chain reaction occurs. The state updates, and every component "listening" to that state via useAppState is notified.
Let's look at a simplified version of the logic inside fast.tsx that combines what we learned.
In the previous chapter, we created the function applyFastMode. Here is how it uses the state setter to not only toggle the flag but also switch the AI model if necessary.
// Inside applyFastMode function in fast.tsx
if (enable) {
// We use the setter we got from the hook
setAppState(prev => {
// Check if current model is too slow for fast mode
const mustSwitch = !isFastModeSupportedByModel(prev.mainLoopModel);
return {
...prev, // Copy existing state
fastMode: true, // Turn on the flag
// If we must switch, change the model too. Otherwise, do nothing.
...(mustSwitch ? { mainLoopModel: 'claude-3-haiku' } : {})
};
});
}
Explanation: This is a powerful pattern. We are conditionally updating multiple parts of the global state at once.
prev).mainLoopModel needs to change.Because we are using this reactive global state, we don't need to manually tell the screen to update.
In fast.tsx, the FastModePicker component is defined like this:
export function FastModePicker({ onDone }) {
// 1. Hook into the state
const enableFastMode = useAppState(s => s.fastMode);
// 2. Render based on that state
return (
<Box>
<Text bold>Fast mode</Text>
{/* The text below changes automatically! */}
<Text color={enableFastMode ? "green" : "gray"}>
{enableFastMode ? "ON" : "OFF"}
</Text>
</Box>
);
}
Because enableFastMode comes from useAppState, the moment our logic function updates the state, this <Text> tag flips from "OFF" to "ON" and turns green.
In this chapter, we learned about Global Application State:
useAppState.useSetAppState.Now that we have our Logic (Chapter 2) and our Data (Chapter 3), we need to actually draw that beautiful interface we just saw in the code snippets.
Next: Terminal UI (TUI) Rendering
Generated by Code IQ