<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: robin okwanma</title>
    <description>The latest articles on Forem by robin okwanma (@robinokwanma).</description>
    <link>https://forem.com/robinokwanma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2549565%2Ffb21fb4f-1dce-4459-b2ea-eadd41fb91dd.jpg</url>
      <title>Forem: robin okwanma</title>
      <link>https://forem.com/robinokwanma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/robinokwanma"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>robin okwanma</dc:creator>
      <pubDate>Fri, 13 Dec 2024 03:01:31 +0000</pubDate>
      <link>https://forem.com/robinokwanma/-1hi</link>
      <guid>https://forem.com/robinokwanma/-1hi</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/robinokwanma" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2549565%2Ffb21fb4f-1dce-4459-b2ea-eadd41fb91dd.jpg" alt="robinokwanma"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/robinokwanma/build-a-weather-app-with-react-native-opencagedata-and-openweathermap-3nf0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Build a Weather App with React Native, OpenCageData, and OpenWeatherMap&lt;/h2&gt;
      &lt;h3&gt;robin okwanma ・ Dec 13&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#reactnative&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mobile&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Build a Weather App with React Native, OpenCageData, and OpenWeatherMap</title>
      <dc:creator>robin okwanma</dc:creator>
      <pubDate>Fri, 13 Dec 2024 03:01:12 +0000</pubDate>
      <link>https://forem.com/robinokwanma/build-a-weather-app-with-react-native-opencagedata-and-openweathermap-3nf0</link>
      <guid>https://forem.com/robinokwanma/build-a-weather-app-with-react-native-opencagedata-and-openweathermap-3nf0</guid>
      <description>&lt;p&gt;Ready to build a real-world weather app? Let's dive in! We'll use the powerful combination of React Native Expo, OpenWeatherMap, and OpenCageData to create a mobile app that delivers accurate and up-to-date weather information.&lt;/p&gt;

&lt;p&gt;First, sign up for a free OpenCageData account. This service is a game-changer, allowing us to fetch location data directly in our browser using its API URL. Once you've signed up, grab your API key and store it securely.&lt;/p&gt;

&lt;p&gt;Next, head over to OpenWeatherMap and create a free account. This platform provides a wealth of weather data that we'll use to power our app. After signing up, retrieve your API key and keep it handy.&lt;/p&gt;

&lt;p&gt;With these essential tools in place, we're ready to start building our weather app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started!&lt;/strong&gt;&lt;br&gt;
If you're new to coding, make sure you have these tools ready:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Node.js&lt;/strong&gt;: Download and install it from the official website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expo CLI&lt;/strong&gt;: Install it globally using this command in your terminal: &lt;br&gt;
&lt;code&gt;npm install -g expo-cli&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expo App&lt;/strong&gt;: Download the Expo app on your phone or tablet to test your app as you build it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1- Create a New Expo Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Open your terminal and run the following command to create a new project named "WeatherHunt":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo init WeatherHunt
cd WeatherHunt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2- Install Essential Tools&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install axios react-native-elements react-native-dotenv

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3: Configure Environment Variables&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We'll use a &lt;code&gt;.env&lt;/code&gt; file to store our API keys and URLs securely. To make this work, we need to configure Babel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open the babel.config.json file in your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the following plugin to the plugins array:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = function(api) {
    api.cache(true);
    return {
        presets: ['babel-preset-expo'],
        plugins: [
            'react-native-reanimated/plugin', ['module:react-native-dotenv', {
                moduleName: '@env',
                path: '.env',
            }],
        ],
    };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're all set to start building your weather app!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4- Organize our project!&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To keep our code clean and easy to understand, we're going to create three new folders:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;screens&lt;/strong&gt;: This is where we'll put the main screen of our app, WeatherHunt.jsx. This screen is where users will search for cities and see the weather.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;config&lt;/strong&gt;: This folder will hold the AccountService.jsx file. This file is like a secret agent, handling all the behind-the-scenes work of talking to the OpenCageData and OpenWeatherMap APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;splashscreen&lt;/strong&gt;: This folder will contain the SplashScreen.jsx file. It's the first thing users see when they open the app, giving a warm welcome while the app gets ready.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This way, we're keeping our UI (the stuff users see) separate from the backend logic (the stuff that makes things work). This makes our code easier to manage and update.&lt;/p&gt;

&lt;p&gt;Here's a quick look at how our project will be structured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WeatherApp/
├── config/
│   └── AccountService.jsx
├── screens/
│   └── WeatherHunt.jsx
├── splashscreen/
│   └── SplashScreen.jsx
├── App.js
├── package.json
├── .expo/
├── node_modules/
└── assets/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By keeping things organized like this, we're setting ourselves up for success!&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5- Set Up the &lt;code&gt;.env&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;To keep your API URLs and tokens secure and easily configurable, we’ll use a .env file. Create a new file named .env in the root of your project and define your variables as shown below. Replace the dummy tokens with your actual API keys from the accounts you set up earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API_URL= https://api.openweathermap.org/data/2.5/weather
API_TOKEN= dummyopenweathermaptoken
GEOCODING_API_URL = https://api.opencagedata.com/geocode/v1/json
GEOCODING_API_TOKEN= dummygeocodingapitoken

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using a .env file, you can separate sensitive data from your codebase, making it easier to manage and secure.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6- Create SplashScreen
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
Let's add a splash screen to give our app a little pizzazz! A splash screen is like a quick hello, a brief moment to greet your users while the app gets ready.&lt;/p&gt;

&lt;p&gt;We'll create a new file called SplashScreen.jsx and put it in the splashscreen folder. This screen will show a short welcome message to keep users entertained while the app loads. Here’s the code for the splash screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { View, Text, StyleSheet } from 'react-native';
import React from 'react';

const SplashScreen = () =&amp;gt; {
  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text style={styles.header}&amp;gt;WEATHER HUNTER&amp;lt;/Text&amp;gt;
      &amp;lt;Text style={styles.description}&amp;gt;Discover the weather for any city or zip code in the world!&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#003366',
    alignItems: 'center',
    justifyContent: 'center',
  },
  header: {
    fontSize: 32,
    fontWeight: 'bold',
    color: '#ffffff',
    marginBottom: 20,
    textAlign: 'center',
  },
  description: {
    fontSize: 18,
    color: '#cccccc',
    textAlign: 'center',
    paddingHorizontal: 20,
  },
});

export default SplashScreen;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7- Make API Calls in &lt;code&gt;AccountService.jsx&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Next, we’ll create a service class to handle API calls. This class centralizes logic for fetching weather data and geocoding coordinates, keeping the main application code cleaner and more manageable. Below is the AccountService.jsx file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AccountService {
  constructor() {
    // OpenWeatherMap API details
    this.baseUrl = process.env.API_URL; // Base URL for weather data
    this.baseToken = process.env.API_TOKEN; // API key for OpenWeatherMap

    // OpenCage API details
    this.geocodingBaseUrl = process.env.GEOCODING_API_URL; // Base URL for geocoding
    this.geocodingApiToken = process.env.GEOCODING_API_TOKEN; // API key for OpenCage
  }

  // Fetch coordinates for a given location (city or zip code)
  async getCoordinates(location) {
    const url = `${this.geocodingBaseUrl}?q=${encodeURIComponent(location)}&amp;amp;key=${this.geocodingApiToken}`;
    const response = await fetch(url);
    if (!response.ok) throw new Error(`Error fetching coordinates: ${response.statusText}`);
    const data = await response.json();
    if (data.results.length === 0) throw new Error("Location not found");
    const { lat, lng } = data.results[0].geometry;
    return { lat, lon: lng };
  }

  // Get city suggestions based on user input
  async getCitySuggestions(query) {
    const url = `${this.geocodingBaseUrl}?q=${encodeURIComponent(query)}&amp;amp;key=${this.geocodingApiToken}`;
    const response = await fetch(url);
    if (!response.ok) throw new Error(`Error fetching city suggestions: ${response.statusText}`);
    const data = await response.json();
    return Array.isArray(data.results)
      ? data.results.map(result =&amp;gt; ({
          name: result.formatted,
          lat: result.geometry.lat,
          lon: result.geometry.lng,
        }))
      : [];
  }

  // Fetch weather data using latitude and longitude
  async getWeather(lat, lon) {
    const url = `${this.baseUrl}?lat=${lat}&amp;amp;lon=${lon}&amp;amp;appid=${this.baseToken}&amp;amp;units=metric`;
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(`Error fetching weather data: ${response.statusText}`);
      const data = await response.json();
      return data;
    } catch (error) {
      console.error("Error fetching weather data:", error);
      throw error;
    }
  }
}

export default new AccountService();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of Methods&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getCoordinates(location)&lt;/strong&gt;: Takes a location name or zip code as input. Fetches latitude and longitude using the OpenCage API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getCitySuggestions(query)&lt;/strong&gt;: Takes a partial or full city name as input. Returns a list of possible matching cities with their coordinates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getWeather(lat, lon)&lt;/strong&gt;: Uses latitude and longitude to fetch weather details from the OpenWeatherMap API.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By encapsulating API logic in AccountService, we ensure clean and reusable code, making it easier to maintain and debug.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  Setp 8- Build the Main Interface Screen
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
Now that we’ve set up the splash screen and the API logic, it’s time to create the main interface of our weather application. This is where users will interact with the app to search for locations and view weather information. The interface includes a search bar for entering a city or zip code, a button to fetch weather data, and a results section to display the fetched weather details.&lt;/p&gt;

&lt;p&gt;Create a new file named WeatherHunt.jsx inside the screens folder and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import {
  View,
  Text,
  ActivityIndicator,
  StyleSheet,
  Modal,
  Image,
  TouchableOpacity,
  KeyboardAvoidingView,
  Platform,
  TouchableWithoutFeedback,
  Keyboard,
} from "react-native";
import AccountService from "../config/AccountService";
import { Input, Button } from "react-native-elements";

const WeatherHunt = () =&amp;gt; {
  const [location, setLocation] = useState("");
  const [weather, setWeather] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [suggestions, setSuggestions] = useState([]);
  const [isModalVisible, setModalVisible] = useState(false);
  const [selectedSuggestion, setSelectedSuggestion] = useState(null);

  const handleSearch = async () =&amp;gt; {
    setLoading(true);
    setError(null);
    setSuggestions([]);

    try {
      const data = await AccountService.getCitySuggestions(location);
      setSuggestions(data);
      setModalVisible(true);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const handleSelectSuggestion = (suggestion) =&amp;gt; {
    setLocation(suggestion.name);
    setSelectedSuggestion(suggestion);
    setModalVisible(false);
  };

  const handleSubmit = async () =&amp;gt; {
    setLoading(true);
    setError(null);
    setWeather(null);

    try {
      let weatherData;
      if (selectedSuggestion) {
        weatherData = await AccountService.getWeather(
          selectedSuggestion.lat,
          selectedSuggestion.lon
        );
      } else {
        const coordinates = await AccountService.getCoordinates(location);
        weatherData = await AccountService.getWeather(
          coordinates.lat,
          coordinates.lon
        );
      }
      setWeather(weatherData);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  // console.log(weather)

  return (
    &amp;lt;TouchableWithoutFeedback onPress={Keyboard.dismiss}&amp;gt;
      &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : null}&amp;gt;
          &amp;lt;Text style={styles.header}&amp;gt;WEATHER HUNTER&amp;lt;/Text&amp;gt;
          &amp;lt;Text style={styles.description}&amp;gt;
            Enter a city or zip code to find the weather information.
          &amp;lt;/Text&amp;gt;
          &amp;lt;View style={styles.searchContainer}&amp;gt;
            &amp;lt;Input
              placeholder="Enter city or zip code"
              value={location}
              onChangeText={(value) =&amp;gt; {
                setLocation(value);
                setSelectedSuggestion(null);
              }}
              containerStyle={styles.inputContainer}
              inputContainerStyle={styles.input}
            /&amp;gt;
            &amp;lt;View style={styles.buttonContainer}&amp;gt;
              &amp;lt;Button
                title="Search"
                onPress={handleSearch}
                buttonStyle={styles.button}
              /&amp;gt;
              &amp;lt;Button
                title="Get Weather"
                onPress={handleSubmit}
                buttonStyle={styles.button}
              /&amp;gt;
            &amp;lt;/View&amp;gt;
          &amp;lt;/View&amp;gt;
          &amp;lt;Modal visible={isModalVisible} transparent={true} animationType="slide"&amp;gt;
            &amp;lt;View style={styles.modalContainer}&amp;gt;
              &amp;lt;View style={styles.modalContent}&amp;gt;
                {loading &amp;amp;&amp;amp; &amp;lt;ActivityIndicator size="large" color="#0000ff" /&amp;gt;}
                {suggestions.map((item, index) =&amp;gt; (
                  &amp;lt;TouchableOpacity
                    key={index}
                    onPress={() =&amp;gt; handleSelectSuggestion(item)}
                  &amp;gt;
                    &amp;lt;Text style={styles.suggestionItem}&amp;gt;{item.name}&amp;lt;/Text&amp;gt;
                  &amp;lt;/TouchableOpacity&amp;gt;
                ))}
                &amp;lt;Button title="Close" onPress={() =&amp;gt; setModalVisible(false)} /&amp;gt;
              &amp;lt;/View&amp;gt;
            &amp;lt;/View&amp;gt;
          &amp;lt;/Modal&amp;gt;
          {loading &amp;amp;&amp;amp; &amp;lt;ActivityIndicator size="large" color="#0000ff" /&amp;gt;}
          {error &amp;amp;&amp;amp; &amp;lt;Text style={styles.error}&amp;gt;{error}&amp;lt;/Text&amp;gt;}
          {weather &amp;amp;&amp;amp; (
            &amp;lt;View style={styles.weatherInfo}&amp;gt;
              &amp;lt;Text style={styles.weatherTitle}&amp;gt;{weather.name}&amp;lt;/Text&amp;gt;
              &amp;lt;Text style={styles.weatherDescription}&amp;gt;
                {weather.weather[0]?.description || "No description available"}
              &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={styles.weatherTemp}&amp;gt;{weather.main.temp} °C&amp;lt;/Text&amp;gt;
              &amp;lt;Image
                style={styles.weatherIcon}
                source={{
                  uri: `http://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`,
                }}
              /&amp;gt;
            &amp;lt;/View&amp;gt;
          )}
        &amp;lt;/KeyboardAvoidingView&amp;gt;
      &amp;lt;/View&amp;gt;
    &amp;lt;/TouchableWithoutFeedback&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    backgroundColor: "#f0f8ff",
    alignItems: "center",
    padding: 20,
  },
  header: {
    fontSize: 26,
    fontWeight: "bold",
    color: "#0059b3",
    marginBottom: 20,
    textAlign: "center",
  },
  description: {
    fontSize: 16,
    color: "#333",
    textAlign: "center",
    marginBottom: 20,
  },
  searchContainer: {
    alignItems: "center",
    justifyContent: "center",
    width: "100%",
  },
  inputContainer: {
    width: 300,
  },
  input: {
    borderColor: "#0059b3",
    borderWidth: 1,
    borderRadius: 8,
    paddingHorizontal: 10,
    backgroundColor: "#fff",
  },
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "space-between",
    width: "100%",
    marginTop: 10,
  },
  button: {
    backgroundColor: "#0059b3",
    borderRadius: 8,
    width: 140,
  },
  modalContainer: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "rgba(0,0,0,0.5)",
  },
  modalContent: {
    width: "80%",
    backgroundColor: "white",
    padding: 16,
    borderRadius: 8,
  },
  suggestionItem: {
    padding: 10,
    borderBottomWidth: 1,
    borderBottomColor: "#ccc",
  },
  error: {
    color: "red",
    marginVertical: 10,
  },
  weatherInfo: {
    marginTop: 20,
    backgroundColor: "#fff",
    borderRadius: 15,
    padding: 30,
    alignItems: "center",
  },
  weatherTitle: {
    fontSize: 24,
    fontWeight: "bold",
    marginBottom: 10,
  },
  weatherDescription: {
    fontSize: 18,
    textTransform: "capitalize",
  },
  weatherTemp: {
    fontSize: 24,
    fontWeight: "bold",
    color: "#0059b3",
    marginBottom: 10,
  },
  weatherIcon: {
    width: 100,
    height: 100,
  },
});

export default WeatherHunt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
Search Bar: Users can input a city or zip code to find weather information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Search" and "Get Weather" Buttons:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Search&lt;/em&gt;&lt;/strong&gt;: Opens a modal with location suggestions based on the Zip code or text. This is useful if different places have the same name or code.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Get Weather&lt;/em&gt;&lt;/strong&gt;: Fetches weather data directly if a specific location is selected or entered.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Weather Information Display&lt;/em&gt;&lt;/strong&gt;: Displays temperature, description, and weather icon when data is fetched.&lt;br&gt;
This step connects the UI with the backend logic, making the app interactive and functional.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 9- Combine Splash Screen and Main Interface&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this final step, we integrate the Splash Screen and the Main Interface (WeatherHunt) into the app's entry point (App.js). This setup ensures that the Splash Screen appears for a few seconds before transitioning to the main weather application screen. The transition is managed using a simple state (showSplash) and the useEffect hook to set a timer.&lt;/p&gt;

&lt;p&gt;Here is the full App.js code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import WeatherHunt from './screens/WeatherHunt';
import SplashScreen from './splashscreen/SplashScreen';

export default function App() {
  const [showSplash, setShowSplash] = useState(true);

  useEffect(() =&amp;gt; {
    const timer = setTimeout(() =&amp;gt; {
      setShowSplash(false);
    }, 4000); // 4 seconds

    return () =&amp;gt; clearTimeout(timer); // Cleanup the timer
  }, []);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;StatusBar style="auto" /&amp;gt;
      {showSplash ? &amp;lt;SplashScreen /&amp;gt; : &amp;lt;WeatherHunt /&amp;gt;}
    &amp;lt;/&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Here is the Live Demo.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faujhgole8pvo9d2i0xac.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faujhgole8pvo9d2i0xac.jpg" alt="weather app by react native using opencageapi and openweather map by robinokwanma 1 " width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dvrktuu2cdtahhnitnf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dvrktuu2cdtahhnitnf.jpg" alt="weather app by react native using opencageapi and openweather map by robinokwanma 2" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxpz2gpds6hu71xiwm30.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxpz2gpds6hu71xiwm30.jpg" alt="weather app by react native using opencageapi and openweather map by robinokwanma 3" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle8pad2k2k0kdsordijv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle8pad2k2k0kdsordijv.jpg" alt="weather app by react native using opencageapi and openweather map by robinokwanma 4" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Congratulations! 🎉 You’ve successfully built a functional and visually appealing live weather application using React Native, Expo, OpenWeatherMap and OpenCageData API. This app includes a splash screen, a searchable interface, and dynamic weather data fetched from an API.&lt;/p&gt;

&lt;p&gt;The complete source code for this project is available &lt;a href="https://github.com/robinokwanma/weatherapp" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Feel free to explore and modify it as needed.&lt;/p&gt;

&lt;p&gt;If you have any questions or face any challenges while building this project, leave a comment below, and I’ll be happy to assist. Happy coding! 🚀&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>api</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Frontend Integration Coming Up Next</title>
      <dc:creator>robin okwanma</dc:creator>
      <pubDate>Tue, 10 Dec 2024 17:58:48 +0000</pubDate>
      <link>https://forem.com/robinokwanma/frontend-integration-coming-up-next-1g1b</link>
      <guid>https://forem.com/robinokwanma/frontend-integration-coming-up-next-1g1b</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/robinokwanma" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2549565%2Ffb21fb4f-1dce-4459-b2ea-eadd41fb91dd.jpg" alt="robinokwanma"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/robinokwanma/building-a-blog-app-with-django-and-react-step-by-step-guide-5f34" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building a Blog App with Django and React: Step-by-Step Guide&lt;/h2&gt;
      &lt;h3&gt;robin okwanma ・ Dec 10&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#django&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#djangocms&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Building a Blog App with Django and React: Step-by-Step Guide</title>
      <dc:creator>robin okwanma</dc:creator>
      <pubDate>Tue, 10 Dec 2024 17:55:32 +0000</pubDate>
      <link>https://forem.com/robinokwanma/building-a-blog-app-with-django-and-react-step-by-step-guide-5f34</link>
      <guid>https://forem.com/robinokwanma/building-a-blog-app-with-django-and-react-step-by-step-guide-5f34</guid>
      <description>&lt;p&gt;Hi there, this won't be your regular blog application using django for simple CRUD operations. NO!&lt;br&gt;
Let's build a feature-rich industrial standard blog application using django and react. To enhance the content creation process, we will use django's CKEditor, a powerful rich-text editor that helps you with all the tools to write engaging and well formatted articles with ease.&lt;/p&gt;

&lt;p&gt;Whether you're a beginner or an experienced developer, this guide will provide you with a comprehensive understanding of full-stack web development. Let's dive right to it!&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;THE BACKEND&lt;/strong&gt;
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Set Up Django Project
&lt;/h2&gt;

&lt;p&gt;In your terminal, navigate to your preferred directory and begin your project. I will call mine robin's blog. Then create your django app, let's call it "blog" for simplicity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject robins_blog
cd robins_blog
python manage.py startapp blog

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create and Activate Virtual Environment (Optional)
&lt;/h2&gt;

&lt;p&gt;It is always advisable to create virtual environment for your django projects so you have more freedom on the packages you wish to install. It ensures local packages don't conflict with global packages. Let's say you want to use a specific older python version, your virtual environment will let you do it for that project alone, without affecting other projects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python -m venv venv&lt;/code&gt;&lt;br&gt;
&lt;code&gt;venv/Scripts/activate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So now we have created our virtual environments, I will just list out all the packages we need to install for our app to work perfectly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Django==5.1.4
djangorestframework==3.15.2
django-filter==24.3
django-cors-headers==4.6.0
django-ckeditor==6.7.2
django-ckeditor-5==0.2.15
django-taggit==6.1.0
dj-rest-auth==7.0.0
django-oauth-toolkit==3.0.1
djangorestframework-simplejwt==5.3.1
PyJWT==2.10.1
oauthlib==3.2.2
pillow==11.0.0
bleach==6.2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Our Model
&lt;/h2&gt;

&lt;p&gt;Let's create our model, go to the blog folder, locate model.py and define the model for Articles. From this model, we set title, slug, content, image, tags, meta title, meta description and published date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models
from ckeditor.fields import RichTextField
from taggit.managers import TaggableManager
from django.utils.text import slugify

class Article(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255, unique=True, blank=True)
    content = RichTextField()
    image = models.ImageField(upload_to='articles/', blank=True, null=True)
    tags = TaggableManager(blank=True)
    published_date = models.DateTimeField(auto_now_add=True)
    meta_title = models.CharField(max_length=255, blank=True, null=True)
    meta_description = models.CharField(max_length=255, blank=True, null=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.title

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Modify Django Settings
&lt;/h2&gt;

&lt;p&gt;Go to the project folder, we named ours "robin's blog" and make the following modifications.&lt;br&gt;
At the top, import os. set Allowed_Hosts to all "[*]", add your app along with some of the packages we installed to the INSTALLED_APPS field, which should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'oauth2_provider',
    'corsheaders',
    'dj_rest_auth',
    'rest_framework.authtoken',
    'blog',
    'ckeditor',
    'ckeditor_uploader',
    'taggit',  
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the CKEditor config to settings and add corsheaders to middleware. It should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'full',
        'height': 300,
        'width': '100%',
    },
}

CKEDITOR_UPLOAD_PATH = 'uploads/'
CKEDITOR_IMAGE_BACKEND = "pillow"

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add restframework configurations to settings which is just a cool way in django you define how you want your api call to behave; I added comments to tell what each line does, you can modify it to whatever suits you. The restframework section in settings should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',  # Add token authentication
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',  # Allow access to all users so it doesnt require a token
    ],
        'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle', #Throttle is a rate limiting technique that limits number of calls on the api
        'rest_framework.throttling.UserRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/hour', #100 calls for anonymous users
        'user': '1500/hour', #1000 calls per hour for authenticated users
    },
        'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        'rest_framework.filters.SearchFilter',
        'rest_framework.filters.OrderingFilter',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    'SEARCH_PARAM': 'search',  # This should match the query parameter you're using in the frontend
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, set media url and media root, usually at the bottom of the settings page under statuc_url, you will have something like this; make sure you imported os at the top&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Crate Serializers.py File
&lt;/h2&gt;

&lt;p&gt;In your app folder, same folder you have your views and models, create a file and name it serializers.py. We have to build the serializer for the model we made earlier, It should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers
import bleach
from bleach import ALLOWED_TAGS
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    clean_content = serializers.SerializerMethodField()
    tags = serializers.StringRelatedField(many=True)
    author = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = [
            'id',
            'title',
            'slug',
            'clean_content',
            'image',
            'tags',
            'published_date',
            'author',
            'meta_title',
            'meta_description',
            # Add other fields if necessary
        ]

    def get_clean_content(self, obj):
        allowed_tags = list(ALLOWED_TAGS) + [
            'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'blockquote', 'strong', 'em', 'u', 's', 'ol', 'ul', 'li',
            'figure', 'figcaption', 'img',
        ]
        allowed_attrs = {
            '*': ['class', 'style'],
            'a': ['href', 'title'],
            'img': ['src', 'alt', 'title', 'width', 'height'],
        }

        return bleach.clean(obj.content, tags=allowed_tags, attributes=allowed_attrs, strip=True)

    def get_author(self, obj):
        return obj.author.first_name + ' ' + obj.author.last_name

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define Your Apis in Views.py
&lt;/h2&gt;

&lt;p&gt;Now, let's write the API views for the Article model. First, we will import the necessary packages, including the Article model and its serializer. We will create API classes to handle the following functionalities: retrieving all articles, fetching specific articles based on a unique identifier like the slug, and searching articles by title, content, or tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# from django.shortcuts import render
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions, status, viewsets, filters
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer

# Create your views here.
class ArticleList(generics.ListAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

class ArticleListView(generics.ListAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [filters.SearchFilter]
    search_fields = ['title', 'content', 'tags__name']  # adjust this based on your model

class ArticleDetailView(generics.RetrieveAPIView):
    lookup_field = 'slug'
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    def get_object(self, slug):
        return get_object_or_404(Article, slug=slug)

    def get(self, request, slug, format=None):
        article = self.get_object(slug)
        serializer = ArticleSerializer(article)
        return Response(serializer.data)

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [filters.SearchFilter]
    search_fields = ['title', 'content', 'tags__name']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Urls for our Views
&lt;/h2&gt;

&lt;p&gt;Now we have created our views, we need a way to access them, and we cannot do so without modifying our url.py file.&lt;br&gt;
First in the url.py file in your project folder, add these urls which are necessary for ckeditor to function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"""
URL configuration for robins_blog project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-auth/', include('rest_framework.urls')),
    path('rest-auth/', include('dj_rest_auth.urls')),
    path('api/', include('blog.urls')),
    path('ckeditor5/', include('ckeditor_uploader.urls')),
    path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your app folder we named "blog" you have to create a url.py file and define the urls for fetching all articles and fetching articles based on slug or id. It should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()

urlpatterns = [
    path('', include(router.urls)),
    path('articles/', views.ArticleListView.as_view(), name='article-list'),
    path('articles/&amp;lt;slug:slug&amp;gt;/', views.ArticleDetailView.as_view(), name='article-detail')
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define Admin, Migrate then Create Super USer
&lt;/h2&gt;

&lt;p&gt;Now we need to modify our admin.py page so when we create superuser we will be able to see our model in our django backend;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from .models import Article

# Register your models here.
class ArticleAdmin(admin.ModelAdmin):
    list_display = ('title', 'published_date', 'author',)
    search_fields = ('title', 'author',)



admin.site.register(Article, ArticleAdmin)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have made all necessary changes, we have to makemigrations and migrate. Run these commands in the terminal.&lt;br&gt;
&lt;code&gt;python manage.py makemigrations blog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python manage.py migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once they are successful, we can create a super user so we can access our django admin panel. Run this command in the terminal and follow the prompt to create a super admin. &lt;br&gt;
&lt;code&gt;python manage.py createsuperuser&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once all this has been completed successfully, we can now run our server. Run this code in your terminal;&lt;br&gt;
&lt;code&gt;python manage.py runserver&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If your setup was correct, you should see the development server running at port 8000 in your terminal. Now simply visiting localhost:8000 or 127.0.0.1:8000 in your browser will launch the application.&lt;/p&gt;

&lt;p&gt;You can visit the django admin panel by going to the url 127.0.0.1:8000/admin or localhost:8000/admin.&lt;/p&gt;

&lt;p&gt;And there you have it for the backend. If successful, you should see this page on your browser;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnd0vttfb0yb312jl8px.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnd0vttfb0yb312jl8px.png" alt="Image description" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then when you click on articles and try to add articles, you should see the beautiful and powerful text editor below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp9r9d89rlfuadfp6zvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp9r9d89rlfuadfp6zvo.png" alt="Image description" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, we made two api urls for fetching articles;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost:8000/api/articles/
loaclhost:8000/api/articles/&amp;lt;slug:slug&amp;gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;THE FRONTEND&lt;/strong&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Setup React Project
&lt;/h2&gt;

&lt;p&gt;Now, let's dive right to it, We are done with the backend and our apis are functional, Let's create our react project.&lt;br&gt;
Open your terminal and navigate to your preferred directory then run the command;&lt;br&gt;
&lt;code&gt;npx create-react-app blog-frontend&lt;/code&gt;&lt;br&gt;
We are naming ours "blog-frontend", you can name it whatever you like.&lt;/p&gt;

&lt;p&gt;We will keep it simple and use plain css and javascript components. No ui-framework, no component overload. But the outcome will still look as nice as you want.&lt;/p&gt;

&lt;p&gt;Once your react app has been created you can simply set up the folder structure and create necessary components. Proper structuring of components is crucial when working with react, especially when working in a team. Your folder structure should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── components/
│   ├── Header.jsx            // Header component
│   ├── Footer.jsx            // Footer component
│   ├── ArticleList.jsx       // Displays the list of articles
│   ├── ArticleDetail.jsx     // Displays details of a specific article
│   ├── HeaderFooter.css      // Shared CSS for Header and Footer
│   ├── ArticleList.css       // CSS for the ArticleList component
│   ├── ArticleDetail.css     // CSS for the ArticleDetail component
│
├── services/
│   ├── AppService.jsx        // Handles API requests
│
├── App.js                    // Main app entry point
├── index.js                  // ReactDOM rendering

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Let's Write the Code for each component.&lt;br&gt;
First, the Article Detail Page&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { fetchArticle } from '../services/AppService';
import Header from '../components/Header';
import Footer from '../components/Footer';
import './ArticleDetail.css';

function ArticleDetail() {
  const { slug } = useParams();
  const [article, setArticle] = useState(null);

  useEffect(() =&amp;gt; {
    fetchArticle(slug)
      .then(response =&amp;gt; setArticle(response.data))
      .catch(error =&amp;gt; console.error('Error fetching article:', error));
  }, [slug]);

  if (!article) {
    return &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;;
  }

  // Resolve full image URL
  const imageUrl = article.image.startsWith('/media/')
    ? `http://192.168.0.180:8000${article.image}` // Replace with your base API URL or Localhost Ip
    : article.image;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Header /&amp;gt;
      &amp;lt;div className="article-detail-container"&amp;gt;
        &amp;lt;div className="article-card"&amp;gt;
          &amp;lt;img
            src={imageUrl}
            alt={article.title}
            className="article-detail-image"
          /&amp;gt;
          &amp;lt;h1 className="article-title"&amp;gt;{article.title}&amp;lt;/h1&amp;gt;
          &amp;lt;div
            className="article-content"
            dangerouslySetInnerHTML={{ __html: article.clean_content }}
          /&amp;gt;
          &amp;lt;div className="article-meta"&amp;gt;
            &amp;lt;p&amp;gt;
              &amp;lt;strong&amp;gt;Tags:&amp;lt;/strong&amp;gt;{' '}
              {article.tags.map(tag =&amp;gt; (
                &amp;lt;span className="tag" key={tag}&amp;gt;
                  {tag}
                &amp;lt;/span&amp;gt;
              ))}
            &amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;
              &amp;lt;strong&amp;gt;Author:&amp;lt;/strong&amp;gt; {article.author}
            &amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;Footer /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default ArticleDetail;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ArticleList&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import { fetchArticles } from '../services/AppService';
import Header from './Header';
import Footer from './Footer';
import './ArticleList.css';

function ArticleList() {
  const [articles, setArticles] = useState([]);

  useEffect(() =&amp;gt; {
    fetchArticles()
      .then(response =&amp;gt; {
        setArticles(response.data.results || response.data); // Adjust based on your API response
      })
      .catch(error =&amp;gt; console.error('Error fetching articles:', error));
  }, []);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Header /&amp;gt;

      &amp;lt;div className="article-list-container"&amp;gt;
        &amp;lt;div className="articles-grid"&amp;gt;
          {articles.map(article =&amp;gt; (
            &amp;lt;div className="article-card" key={article.id}&amp;gt;
              &amp;lt;img
                src={article.image || 'https://via.placeholder.com/150'}
                alt={article.title}
                className="article-image"
              /&amp;gt;
              &amp;lt;div className="article-content"&amp;gt;
                &amp;lt;h2 className="article-title"&amp;gt;{article.title}&amp;lt;/h2&amp;gt;
                &amp;lt;p className="article-meta"&amp;gt;{article.meta_description}&amp;lt;/p&amp;gt;
                &amp;lt;a href={`/article/${article.slug}`} className="read-more"&amp;gt;
                  Read More
                &amp;lt;/a&amp;gt;
              &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;Footer /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default ArticleList;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Footer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import './HeaderFooter.css'; // Shared styles for Header and Footer

function Footer() {
  return (
    &amp;lt;footer className="footer"&amp;gt;
      &amp;lt;p&amp;gt;Designed with 💗 by Robin Okwanma&amp;lt;/p&amp;gt;
    &amp;lt;/footer&amp;gt;
  );
}

export default Footer;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Header&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import './HeaderFooter.css'; // Shared styles for Header and Footer

function Header() {
  return (
    &amp;lt;header className="header"&amp;gt;
      &amp;lt;h1 className='title'&amp;gt;Robin's 😁 Blog&amp;lt;/h1&amp;gt;
    &amp;lt;/header&amp;gt;
  );
}

export default Header;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AppService File Where we are making our API calls&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import axios from 'axios';

const API = axios.create({ baseURL: 'http://192.168.0.180:8000/api/' });

// Fetch all articles
export const fetchArticles = () =&amp;gt; API.get('articles/');

// Fetch a single article by slug
export const fetchArticle = slug =&amp;gt; API.get(`articles/${slug}/`);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;App.js file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ArticleList from './components/ArticleList';
import ArticleDetail from './components/ArticleDetail';
// import './App.css';

function App() {
  return (
    &amp;lt;Router&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path="/" element={&amp;lt;ArticleList /&amp;gt;} /&amp;gt;
        &amp;lt;Route path="/article/:slug" element={&amp;lt;ArticleDetail /&amp;gt;} /&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/Router&amp;gt;
  );
}

export default App;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, Let's Add Styling to the page we created, You can play around with the colors and style to whatever you like;&lt;br&gt;
ArticleDetail.css&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Container */

.article-detail-container {
    max-width: 800px;
    margin: 40px auto;
    padding: 20px;
    display: flex;
    /* Enable Flexbox */
    justify-content: center;
    /* Center horizontally */
    align-items: center;
    /* Center vertically */
    text-align: center;
    /* background-color: #333; */
    /* Dark background for contrast */
    min-height: 100vh;
    /* Make it take the full viewport height */
}


/* Image Styling */

.article-detail-image {
    width: 100%;
    height: auto;
    border-radius: 8px 8px 0 0;
    /* Rounded corners at the top */
    margin-bottom: 20px;
    /* Space between the image and the title */
    object-fit: cover;
    /* Ensures the image maintains its aspect ratio */
}


/* Card styling */

.article-card {
    background-color: #007bff;
    /* Blue background */
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    width: 100%;
    /* Full width within the container */
    max-width: 600px;
    /* Limit the maximum width */
}


/* Title */

.article-title {
    font-size: 2rem;
    color: #fff;
    /* White color for title */
    margin-bottom: 20px;
}


/* Content */

.article-content {
    text-align: left;
    font-size: 1rem;
    color: #f0f0f0;
    /* Light gray for text */
    margin-bottom: 20px;
}


/* Metadata (Tags and Author) */

.article-meta {
    text-align: left;
    font-size: 0.9rem;
    color: #ccc;
    /* Light gray for metadata */
}

.tag {
    display: inline-block;
    margin: 0 5px;
    padding: 5px 10px;
    background-color: #091a7c;
    border-radius: 15px;
    font-size: 0.8rem;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ArticleList.css&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* General styling */

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f9f9f9;
}

.article-list-container {
    text-align: center;
}


/* Responsive grid */

.articles-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 50px;
    margin: 40px;
    /* Adds space between grid items */
    justify-items: center;
}


/* Article card */

.article-card {
    background-color: #fff;
    border: 1px solid #ddd;
    border-radius: 8px;
    overflow: hidden;
    width: 100%;
    max-width: 300px;
    transition: transform 0.2s;
    margin: 15px;
    /* Adds additional margin between cards */
}

.article-card:hover {
    transform: translateY(-5px);
}

.article-image {
    width: 100%;
    height: 150px;
    object-fit: cover;
}

.article-content {
    padding: 15px;
}

.article-title {
    font-size: 1.2rem;
    margin: 0 0 10px;
    color: #222;
}

.article-meta {
    font-size: 0.9rem;
    color: #666;
    margin: 0 0 15px;
}


/* Updated Read More button */

.read-more {
    display: inline-block;
    padding: 8px 12px;
    background-color: #222;
    /* Matches footer background */
    color: #fff;
    text-decoration: none;
    border-radius: 5px;
    font-size: 0.9rem;
}

.read-more:hover {
    background-color: #444;
    /* Slightly lighter on hover */
}


/* Footer styling */

.footer {
    margin-top: 50px;
    background-color: #222;
    color: #fff;
    padding: 15px 0;
    text-align: center;
    font-size: 0.9rem;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HeaderFooter.css&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.header {
    background-color: #007bff;
    color: #fff;
    padding: 5px 0;
    text-align: center;
    font-size: 1.5rem;
    position: sticky;
    margin-bottom: 30px;
}

.title {
    font-size: 2rem;
}

.footer {
    margin-top: 50px;
    background-color: #222;
    color: #fff;
    padding: 15px 0;
    text-align: center;
    font-size: 0.9rem;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have now completely set up our react frontend, you can run the server by the command &lt;code&gt;npm start&lt;/code&gt; in your terminal. And you should see your frontend running. Here is what it looks like;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmv1pyyti16rn5ms0vj65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmv1pyyti16rn5ms0vj65.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0cmczu4lssqqotgk4lf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0cmczu4lssqqotgk4lf.png" alt="Image description" width="384" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on read more goes to the article detail page just as we programmed in the App.js page.... Whatever text formatting you set on your backend reflects perfectly in the front.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b3g1zqznphijd8eutbu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b3g1zqznphijd8eutbu.png" alt="Image description" width="800" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a live blog I built using the same technology(django and react), &lt;a href="https://techhive.ng/blog" rel="noopener noreferrer"&gt;https://techhive.ng/blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Few Things To Look Out For
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When working with localhost, you should use your local ip instead of localhost or 127.0.0.1:8000. You can do this by simply adding it when running your django server. Like this, &lt;code&gt;python manage.py runserver 198.168.1.56:8000&lt;/code&gt; replace the ip with whatever your network ip is. This will help you call your django APIs from react.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the django settings we added throttling, you can reduce or increase this at will&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the link to the github repo for the &lt;a href="https://github.com/robinokwanma/robins-blog-backend" rel="noopener noreferrer"&gt;backend&lt;/a&gt; and &lt;a href="https://github.com/robinokwanma/robins-blog-frontend" rel="noopener noreferrer"&gt;frontend&lt;/a&gt; of this project, If you run into any errors or have any questions, please let me know in the comments.&lt;/p&gt;

</description>
      <category>django</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
