Explore Duet AI to assist with React frontend application development
Introduction
This post provides an example to explore how Google Cloud’s Duet AI for Developers can assist with frontend application development.
With the help of Duet AI, we use React and TypeScript to build a client-side web app. This simple Weather Application allows user to search for locations and displays its current weather conditions. Along the way, we will learn DuetAI’s assistive capabilities in following areas:
- Bootstrapping an app with
create-react-app
- Using React with TypeScript
- React Hooks
- Async Communication and integrate with Open Weather service API
- Basic Styling
Requirements
- DuetAI project setup
- DuetAI compatible IDE setup
- NodeJS
- Basic familiarity with using the terminal
- Free OpenWeatherMap API key
Step 1: Boot-strapping an App with create-react-app
You can use the following prompt to create a skeleton of TypeScript based React project
Prompt
Show me step by step how to create an react application as name of weather-react-app, using npx with the latest versions and typescript templates
Response
DuetAI will provide detailed steps, include the following command to create React application,
npx create-react-app weather-react-app --template typescript
cd weather-app
npm install
npm start
You will get the following project file structure:
Let’s cleanup the default files
Remove the contents of App.css and index.css
Remove the import of logo.svg from App.tsx
Delete App.test.tsx and logo.svg,
Open src/app.tsx file, Update the definition of the App function (component) :
Next, update the main page app.tsx, to show up “Weather App”
Prompt
Update App.tsx only shows Weather App in a div
Response (app.tsx)
import React from 'react';
function App() {
return (
<div>
<h1>Weather App</h1>
</div>
);
}
export default App;
...
Run “npm start”, the following page will show up:
Step 2: Initial layout: Table of Locations with Search Button
Let’s design an initial round of main page with following elements:
Div 1 for Location Search:
- Text label: “Add Location”
- Text box
- Button, “Search”
- Text Label: Locations
Div 2 for table as list of locations:
- Text label: “Location”
- Table
Prompt
In app.tsx component, within Weather App Div, add a div, include “Add location” Label, a text input box with default value “New York”, a Search button
Add another Div, include h2 text “Location”, follow by a table, head row with Name only, 2 rows with New York, Belfast
The layout does not look well, let’s see how to improve it with bootstrap styles.
Run the “npm install bootstrap” command in project folder,
Add the following statement inside index.tsx so that all pages can leverage bootstrap styles:
import ‘bootstrap/dist/css/bootstrap.min.css’;
Prompt
Update the app.tsx page with proper bootstrap css class Names so that the page looks professional page, set Search button to blue color
The main page will look like after apply bootstrap styles with DuetAI response:
With the static layouts in place, we need to define a few state variables and hook element event handler:
Prompt
Define a locationSearch state variable and set useState initial value to empty string, link “Add Location” text input value and onChange event to this variable. Add locations state variable and set useState initial values to array of strings, update table rows, for each row’s values to map location value in locations state variable
Noted following state variable and event handler will be created:
const [locations, setLocations] = useState<string[]>([]);
const addLocation = (location: string) => setLocations([location, ...locations]);
Rename handleSearch to addLocation, inside function, change locations value to append the locationSearch variable value, update locationSearch variable to empty string. Define a boolean constant called disableSearch and assign its value to if locationSearch.trim is ‘’. Link Search button disable attribute to this variable
Step 3: — Separate LocationSearch and LocationTable Components out from app.tsx
Let’s keep the main component app.tsx as thin as possible, and separate into 2 new components, LocationSearch.tsx and LocationTable.tsx, DuetAI can help with code re-structure too:
Prompt (create LocationSearch Component)
Add a component called LocationSearch.tsx, expose it use FC as arrow function as strong type, define onSearch property, move the elements Label “Add Location”, Input Textbox, “Search” Buttom from App.tsx to this LocationSearch component
Then, define an event handler function to hook-up with the Search button onclick event:
Prompt( define addLocation event handler hook with button onclick event)
Add a addLocation event handler, call onSearch function to pass locationSearch parameter, then setLocation to ‘’. Link addLocation event to Search button’s onclick event
Prompt (create LocationTable Component)
Add a LocationTable component by creating a file called LocationTable.tsx, expose it use FC as arrow function as strong type,, define locations property as string array, move the elements Label “Location”, fowllowed by table, head and body, use location and index for rows from App.tsx to this locationSearch component
Also, app.tsx component will be updated based on the previous responses:
import React, {useState} from 'react';
import './App.css';
import {LocationSearch} from "./LocationSearch";
import {LocationTable} from "./LocationTable";
function App() {
const [locations, setLocations] = useState<string[]>([]);
const addLocation = (location: string) => setLocations([location, ...locations]);
return (
<div className="container">
<h1>Weather App</h1>
<LocationSearch onSearch={addLocation}/>
<LocationTable locations={locations}/>
</div>
);
}
export default App;
Step 4: — Integrate Open Weather API
Go to OpenWeatherMap, get a free API key if you have not done that yet
Before we move ahead, let’s re-organize the project file structure:
Create 3 new sub folders under src: src/components, src/services, src/models
Move app.tsx, app.css, LocationSerarch.tsx, LocationTable.tsx to components folder
Under src/models, create Weather.ts, then
Prompt (Weather.ts)
In Weather.ts model, export 2 subsets, first subset Coordinates with lon as number, lat as number, define another subset WeatherLocation with Coord as Coordinates, id as number, name as string
Under src/services folder, WeatherService.ts then
Prompt (WeatherService.ts)
In WeatherService.ts, define a key string variable to get string value environment variable REACT_APP_OPEN_WEATHER_API_KEY, set keyQuery string value to “appid” append with key, set server string value to ‘api.openweathermap.org/data/2.5'
Remove getWeather function, add searchLocation async function with parameter name Term, fetch results from weather server with query string term and keyQuery, return json data format, add error handling for code ‘400’ or code not ‘200’,
In WeatherService.ts, update searchLocation async function to return WeatherLocation or undefined
Make sure WeatherService.ts looks similar to the following:
const key = process.env.REACT_APP_OPEN_WEATHER_API_KEY;
const keyQuery = `appid=${key}`;
const server = 'api.openweathermap.org/data/2.5';
export const searchLocation = async (term: string) => {
const response = await fetch(`${server}/weather?q=${term}&${keyQuery}`);
if (response.status === 400) {
throw new Error('Invalid city name');
} else {
throw new Error('Something went wrong');
}
return response.data;
// else
};
Then, update LocationSearch.tsx as necessary:
Prompt (LocationSearch.ts)
Update AddLocation event handler, as async function with parameter term as string, set location value to call searchLocation function in services/WeatherService.ts
Step 5: — Showing weather data in the page
As final step of this simple Weather application, we will show the weather data by calling weather API.
First, need to add a currentLocation state variable to app.tsx component:
Prompt (components/app.tsx)
In App.tsx, add a currentLocation state variable as WeatherLocation, update LocationTable with currentLocation property and onselect event
Prompt (components/LocationTable.tsx)
in LocationTable.tsx, add currentLocation,onSelect to LocationTableProps, update table row onclick function to onSelect
Also, need to add more properties to Models/Weather.ts
Prompt (models/Weather.ts)
Extend Weather.ts model, add model WeatherCondition, with fields id, main, description, icon, another model MainWeatherData, with numeric fields temp, feels_like,temp_min,temp_max,pressure, humidity, update Weather model to only include fields: dt as number, weather as WeatherCondition array, main as MainWeatherData
Then, add 2 more functions(readWeather, getIconURL) to WeatherService.ts
Prompt (services/WeatherService.ts)
In WeatherService.tsx, expose a function readWeather to read the current weather using openWeather API at a specified location, use parameter locationID as number return Weather object, expose another helper function to generate location icon urls, use code as string parameter and return string
Now, we need to create 2 more page components to display weather data:
- Create components/WeatherEntry.tsx file, then
Prompt (components/WeatherEntry.tsx)
In WeatherEntry.tsx, define WeatherEntryProps to include weather as type of Weather object, add a inline helper function “convertUnixTimeToDate” to convert unitUTC from number to DateTime, expose WeatherEntry as weather props, and include the following weather elements in divs, Date element to convert weather.dt to local datetime, weather.mainWeather data elements: temp, temp_min, temp_max, humidity, image icon element with url from calling getIconURL function by passing WeatherCondition icon value
2. Create components/WeatherSummary.tsx file, then
Prompt (components/WeatherSummary.tsx)
In WeatherSummary.tsx component, define WeatherSummary props, include location field as WeatherLocation or null. Expose WeatherSummary function to return location, include a weather state variable initialized with Weather or null object, follow by useEffect function to readWeather from location.id, if location.id has value, setWeather
3. In app.tsx, add WeatherSummary information
Prompt (components/app.tsx)
In app.tsx component, add another div to include WeatherSummary info, also import WeatherSummary.tsx
Please be noted, exact results from Step 5, might varies significantly, you may use cautions and adjust your prompts accordly. Check with the github links to the files if you get stumbled in this step.
Run the following command to give a try:
export REACT_APP_OPEN_WEATHER_API_KEY=YourOpenWeatherAPIKey;
npm start
You will see a page can search a location and show real-time weather data conditions:
Final thoughts
In this post, we walked through the main steps to build a simple React based frontend application with integration of real time weather service API data.
A few take aways using Google DuetAI for developer to accelerate client based application development:
- Be Specific on Prompts: Be clear and specific on context, leads to the better Duet AI responses.
- Foundational understanding on React framework: Solid understanding of React and framework concepts( such as state variables, event hooks etc.) will make Duet AI responses more relevant and productive.
- Duet AI as assistive tool: Use Duet AI for help and guidance, use judgement to adopt code generated. Be cautious and not to blindly copy-paste
- Duet AI as virtual Pair-programmer: Just like in-person one, be patient and start with basics, gradually improve the quality with more iterations. Occasionally you may still need to jump in and resolve simple issues such as missing import modules, inconsistency of function names across different components. After all, Duet AI is really good to remember stuff and learn from you as well
Don’t forget to check out the best practices to write better Duet AI prompt, For your reference, all the code snippets and final solution for the weather app related to this blog can be find in this source code repo