A Step-by-Step Guide to Building a Full-Stack TypeScript Weather App with Node.js, React, and Tailwind CSS
In this guide, I will walk you through building a full-stack TypeScript weather app using Node.js, React, and Tailwind CSS. This app will fetch weather data from a third-party API, display the current weather, and provide a forecast for the next five days.
Prerequisites:
Before we begin, make sure you have the following installed on your system:
Node.js and npm (latest LTS version recommended)
A code editor like Visual Studio Code
A basic understanding of TypeScript, React, and Node.js
Step 1: Set up the project structure
First, let's create a new folder for our project and navigate into it:
mkdir weather-app
cd weather-app
Next, create a client
folder for the React app and a server
folder for the Node.js server:
mkdir client server
Step 2: Set up the Node.js server
Navigate to the server
folder and initialize a new Node.js project with TypeScript:
cd server
npm init -y
npm install typescript ts-node @types/node --save-dev
npx tsc --init
Edit the tsconfig.json
file to enable the "esModuleInterop
" option:
{
"compilerOptions": {
"esModuleInterop": true,
...
}
}
Install Express, Axios, and their respective types:
npm install express axios
npm install @types/express @types/axios --save-dev
Create a file named index.ts
in the server
folder and set up a basic Express server:
import express from 'express';
const app = express();
const PORT = process.env.PORT || 3001;
app.get('/', (req, res) => {
res.send('Hello from the weather app server!');
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Add a start script to the server/package.json
file:
"scripts": {
"start": "ts-node index.ts"
}
Test the server by running npm start
. You should see the message "Server is running on port 3001".
Step 3: Set up the React app
Navigate to the client
folder and create a new React app using the create-react-app
template:
cd ../client
npx create-react-app . --template typescript
Install the necessary dependencies:
npm install axios react-query tailwindcss@latest postcss@latest autoprefixer@latest
Initialize Tailwind CSS:
npx tailwindcss init
Add the following to your tailwind.config.js
file:
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
darkMode: false,
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
Configure PostCSS by creating a postcss.config.js
file in the client
folder:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Import the Tailwind CSS styles in the src/index.css
file:
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
Step 4: Fetch and display weather data
Now, let's fetch the weather data from a third-party API, such as OpenWeatherMap. Sign up for a free account and get your API key.
In the server/index.ts
file, add an endpoint to fetch weather data using Axios:
import axios from 'axios';
// Replace YOUR_API_KEY with your actual API key from OpenWeatherMap
const API_KEY = 'YOUR_API_KEY';
app.get('/weather/:city', async (req, res) => {
const city = req.params.city;
try {
const response = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`
);
res.json(response.data);
} catch (error) {
res.status(500).send('Error fetching weather data');
}
});
In the client/src
folder, create a new file named useWeather.ts
to fetch weather data using React Query:
import { useQuery } from 'react-query';
import axios from 'axios';
const fetchWeather = async (city: string) => {
const response = await axios.get(`/weather/${city}`);
return response.data;
};
export const useWeather = (city: string) => {
return useQuery(['weather', city], () => fetchWeather(city));
};
Create a new WeatherCard.tsx
component to display the weather data:
import React from 'react';
interface WeatherCardProps {
weatherData: any;
}
const WeatherCard: React.FC<WeatherCardProps> = ({ weatherData }) => {
return (
<div className="bg-white p-6 rounded-md shadow-md">
<h2 className="text-xl font-bold">
{weatherData.name}, {weatherData.sys.country}
</h2>
<p className="text-gray-600">{weatherData.weather[0].description}</p>
<p className="text-4xl font-bold">
{Math.round(weatherData.main.temp)}°C
</p>
</div>
);
};
export default WeatherCard;
Now, update the src/App.tsx
file to fetch and display the weather data using the useWeather
hook and WeatherCard
component:
import React, { useState } from 'react';
import './App.css';
import WeatherCard from './WeatherCard';
import { useWeather } from './useWeather';
function App() {
const [city, setCity] = useState('London');
const { data, isLoading, isError } = useWeather(city);
const handleSearch = () => {
// Add your search logic here
};
return (
<div className="App">
<header className="App-header">
<h1>Weather App</h1>
<input
type="text"
placeholder="Search by city"
value={city}
onChange={(e) => setCity(e.target.value)}
/>
<button onClick={handleSearch}>Search</button>
{isLoading && <p>Loading...</p>}
{isError && <p>Error fetching weather data</p>}
{data && <WeatherCard weatherData={data} />}
</header>
</div>
);
}
export default App;
You now have a basic full-stack TypeScript weather app using Node.js, React, and Tailwind CSS. You can expand this app by adding a five-day forecast, error handling, and user input validation.
What would you add or change? Sign off in the comments!