Welcome to the final chapter of our tutorial series!
In the previous chapter, Context Injection, we learned how the application gathers data (like git changes) and injects it into our command. We ended with our Handler holding a bag of data, ready to hand it off.
In this chapter, we build the React Component Bridge. This is the destination where our data finally becomes something the user can see and interact with.
We have a disconnect.
Imagine a Universal Remote Control (The Handler) and a TV Screen (The Component).
We need a way to connect them so the Remote can tell the TV what to show, and the TV can tell the Remote when the user is done watching.
In React, the "Bridge" is built using Props (Properties). Props are how we pass signals from the logic layer down to the visual layer.
For our diff tool, we need to pass two specific things across the bridge:
Let's build DiffDialog.tsx to accept these signals.
First, we define the "sockets" on the back of our TV. We need to tell TypeScript exactly what signals this component accepts.
// --- File: components/diff/DiffDialog.tsx ---
import * as React from 'react';
import { Text, Box, useInput } from 'ink';
// 1. Define the Bridge connection points
type Props = {
messages: string[]; // The Data
onDone: () => void; // The Power Button
};
Explanation:
messages: We expect an array of text strings (the file diffs).onDone: We expect a function that takes no arguments. Calling this function shuts down the command.
Next, we create the component itself. It takes the messages prop and turns it into visual text.
// ... continued
export const DiffDialog = ({ messages, onDone }: Props) => {
// 2. Render the data
return (
<Box flexDirection="column" borderStyle="round">
<Text bold>Changed Files:</Text>
{messages.map((msg, index) => (
<Text key={index} color="green">
{msg}
</Text>
))}
</Box>
);
};
Explanation:
Box and Text: These are components from ink. Think of Box like a <div> and Text like a <span>, but for the terminal.messages.map: We loop through every message in our data and create a green text line for it.messages) and converted it into a visual element (<Text>).
The user can see the changes, but they are stuck! They can't exit the screen. We need to wire up the "Power Button" using the onDone prop.
// ... inside DiffDialog component
// 3. Listen for key presses
useInput((input, key) => {
// If user presses "Escape" or "q"
if (key.escape || input === 'q') {
// PRESS THE POWER BUTTON!
onDone();
}
});
// ... return JSX
Explanation:
useInput: This is a hook that listens to your keyboard.onDone(): This is the crucial moment. The Component (TV) calls the function given to it by the Handler (Remote). This triggers the cleanup process in the main application.It is important to understand the direction of data and control.
Here is the lifecycle of the Bridge:
DiffDialog and passes messages.DiffDialog draws the text on the terminal.DiffDialog calls onDone.
The file diff.tsx (The Handler) and DiffDialog.tsx (The Component) work together as a unit.
In Local JSX Handler, we saw this line:
// From diff.tsx
return <DiffDialog messages={context.messages} onDone={onDone} />;
And now in this chapter, we see the receiving end:
// From DiffDialog.tsx
export const DiffDialog = ({ messages, onDone }: Props) => ...
This matching of attributes (messages={...}) to function arguments ({ messages }) is the definition of the React Component Bridge. It allows us to keep our "Math" code completely separate from our "Art" code.
Congratulations! You have completed the React Component Bridge chapter, and with it, the entire basic tutorial for the diff project.
Let's review what we built together:
index.ts).diff.tsx).You now have a fully functional feature that integrates seamlessly into the application architecture. You understand how to register, load, inject, and display data using the power of React in the terminal.
Happy Coding!
Generated by Code IQ