30
loading...
This website collects cookies to deliver better user experience
onClick
, onSubmit
, and HTTP calls. But Remix handles this situation in a completely different way by providing functions like action
and loader
to perform server-side operations. Form data is easily available in these functions. This means there’s absolutely no need to serve JavaScript to the frontend to submit a form.fetch
or an axios
call, but you don’t need to do that in Remix. It helps keep things simple.npx create-remix@latest weather-app
weather-app
with whatever project name is suitable to you. Once you hit Enter
, you will see an interactive menu that will help you make a Remix app.npm install
. Type y
. This will install the required dependencies for Remix to run.npm install axios dotenv
axios
so that we can send HTTP requests from our app to the OpenWeatherMap API. We will be using dotenv
for storing our API key in an environment variable.package.json
so that we can use environment variables in the development mode of Remix. Replace the dev
script with the following:"dev": "node -r dotenv/config node_modules/.bin/remix dev"
.env
for our environment variables and store the API key in the following format:WEATHER_API_KEY={api key here}
app
folder contains our main app logic. All the folders and files under the routes
folder are exposed to the public and can be accessed with a URL. The styles
folder contains all the CSS files, which are stored in a similar fashion as routes.entry.client.jsx
and entry.server.jsx
are managed by Remix, and it’s better not to touch entry files. Instead, create new files and work on them. The root.jsx
file contains our general page layout.public
folder contains our public assets like static images and favicons, and the remix.config.js
file contains basic configuration for our Remix app, such as the port it should run on in development mode.root.jsx
and empty the default Layout
component so that it looks like this:function Layout({ children }) {
return <div>{children}</div>;
}
styles
folder, remove the demos
folder, and empty the contents of dark.css
and global.css
. This will clean up all the styling for us.demos
folder in the routes
directory as well because we don’t need it.index.jsx
and empty everything. Just make sure it has a default exported component just like this:export default function Index() {
return <div></div>;
}
index.jsx
with the following layout:export default function Index() {
return (
<div>
<form action="/weather" method="get">
City: <input type="text" name="city" />
<input type="submit" value="Fetch weather" />
</form>
</div>
);
}
get
, and we have a name associated with the input field, which will be appended to the URL when the form gets submitted.weather.jsx
in the routes
folder; it will handle the /weather
route:import { Outlet } from "react-router";
export default function Weather() {
return (
<>
<h1>Weather App</h1>
<Outlet />
</>
);
}
Outlet
component will look for the weather
folder inside the routes
folder and embed the pages inside the main page. This should give you an idea on how page nesting works in Remix.routes
named weather
, and create a new file index.jsx
inside the weather
folder. Let’s make a loader
function that will run on the server side whenever the page is requested:export async function loader({ request }) {
try {
const url = new URL(request.url);
const search = new URLSearchParams(url.search);
if (!search.get("city")) return redirect("/");
const city = search.get("city");
const res = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}&units=metric`
);
console.log(res.data);
return { city, type: res.data.weather[0].main, temp: res.data.main.temp };
} catch (err) {
console.error(err);
redirect("/");
return {};
}
}
export default function Index() {
const data = useLoaderData();
return (
<div>
<h1>{data.city}</h1>
<h2>{data.type}</h2>
<h3>Temperature: {data.temp} °C</h3>
</div>
);
}
useLoaderData
hook gets the data that was returned using the loader
function so that we can render it on the frontend. If you did everything correctly, you should get your weather rendered like this: