<?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>DEV Community: frank edekobi</title>
    <description>The latest articles on DEV Community by frank edekobi (@qobi).</description>
    <link>https://dev.to/qobi</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%2F1498999%2F4b5cc379-5662-4b72-9018-e232d8f7c496.png</url>
      <title>DEV Community: frank edekobi</title>
      <link>https://dev.to/qobi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/qobi"/>
    <language>en</language>
    <item>
      <title>Upgrade Your React App with Vite: Faster Builds, Real-Time ESLint Feedback, and Cleaner Files</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Mon, 10 Feb 2025 14:36:58 +0000</pubDate>
      <link>https://dev.to/qobi/upgrade-your-react-app-with-vite-faster-builds-real-time-eslint-feedback-and-cleaner-files-132p</link>
      <guid>https://dev.to/qobi/upgrade-your-react-app-with-vite-faster-builds-real-time-eslint-feedback-and-cleaner-files-132p</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is this tutorial about?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This guide will walk you through setting up Vite for a faster and simpler development experience. We'll also configure ESLint to help catch issues as you code. Finally, we'll clean up unnecessary files from your project and organize the structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why go through all this work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switching to Vite speeds up and simplifies development. It updates changes instantly and keeps everything lightweight, with less setup and fewer headaches. Vite is perfect for projects with TypeScript, React, or Vue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who is this tutorial for?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This guide is for developers who are used to Create React App or Webpack and want to try out a faster, simpler build tool without changing much code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Vite helps make your project run faster and easier to manage. Here are the key reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast Reloads: Vite instantly updates your project as you code.&lt;/li&gt;
&lt;li&gt;Less Setup: Vite has a simpler configuration, so there are fewer files to manage.&lt;/li&gt;
&lt;li&gt;Better Performance: Vite is optimized for speed, both in development and when building for production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's begin&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Step 1: Moving to Vite&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Install Vite: Open your terminal, go to your project folder, and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install vite @vitejs/plugin-react --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D vite @vitejs/plugin-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move index.html: In a Vite project, index.html should be in the root of the project (not in the public folder). Move it by:&lt;br&gt;
Cutting index.html from the public folder.&lt;br&gt;
Pasting it directly into your main project folder.&lt;/p&gt;

&lt;p&gt;Edit index.html: In the moved index.html file, add the script tag with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="module" src="/src/index.tsx"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Vite to load your app's code from src/index.tsx, so it knows where to start.&lt;/p&gt;

&lt;p&gt;Also, replace %PUBLIC_URL% with / in the index.html file, as Vite doesn't use this syntax. Here's how:&lt;/p&gt;

&lt;p&gt;Open index.html: Go through the index.html file and look for any occurrences of %PUBLIC_URL%.&lt;/p&gt;

&lt;p&gt;Replace %PUBLIC_URL% with /: For example, if you see something 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;&amp;lt;link rel="icon" href="%PUBLIC_URL%/favicon.ico" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update Package Scripts: Open package.json and replace your old start, build, and test scripts with Vite's commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {   
   "dev": "vite",   
   "build": "vite build",   
   "serve": "vite preview" 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a Basic Vite Configuration File: In the root of your project, create a vite.config.js file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig } from 'vite'; 
import react from '@vitejs/plugin-react';  

export default defineConfig({   
  plugins: [react()] 
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file sets up Vite to work with React.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Step 2: Setting Up ESLint for Real-Time Code Feedback&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To check your code for mistakes as you work, follow these steps to set up ESLint:&lt;/p&gt;

&lt;p&gt;Install ESLint and Plugins: Run the following in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin vite-plugin-eslint --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin vite-plugin-eslint 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add ESLint Configuration: Create an .eslintrc.js file in your root folder and add this configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {   
   parser: '@typescript-eslint/parser',   
   plugins: ['@typescript-eslint'],   
   extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended'  ],   
   rules: {     // Add any additional ESLint rules here   } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Link ESLint with Vite: Open your vite.config.js file again and add the ESLint plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig } from 'vite'; 
import react from '@vitejs/plugin-react';
import eslint from 'vite-plugin-eslint';  

export default defineConfig({   
  plugins: [react(), eslint()], 
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run Your Dev Server with ESLint: Now, start your development server:&lt;br&gt;
ESLint should show any issues in the terminal or your code editor.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Step 3: Cleaning Up Unnecessary Files&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After switching to Vite, you can remove the following files:&lt;br&gt;
Webpack Config Files: webpack.config.js or similar files related to Webpack setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Babel Configuration Files: If you're not using Babel, you can delete .babelrc or babel.config.js.&lt;/li&gt;
&lt;li&gt;Unused public Folder Content: Since index.html is now in the root, you can delete it from the public folder. If you have other files in public you don't need anymore, clean them out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Step 4: Test Your Vite Setup&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To check everything is working:&lt;br&gt;
Start Development Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will open the app, and you'll see updates instantly when you make changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Wrapping Up&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You're now ready to use Vite for faster development! With ESLint, you can catch issues as you code, and the cleanup removes unnecessary files. Enjoy your improved development setup!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to display IP camera feed from an RTSP url onto react app page with node js</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Mon, 16 Sep 2024 17:53:28 +0000</pubDate>
      <link>https://dev.to/qobi/how-to-display-ip-camera-feed-from-an-rtsp-url-onto-react-app-page-with-node-js-516l</link>
      <guid>https://dev.to/qobi/how-to-display-ip-camera-feed-from-an-rtsp-url-onto-react-app-page-with-node-js-516l</guid>
      <description>&lt;p&gt;Refactor it however you please, but this should give you the essential building blocks to successfully render the rtsp stream in a react js app from a node js app.&lt;br&gt;
Also make sure the rtsp feed is valid, you can test it using vlc media app.&lt;br&gt;
and make sure you have ffmpeg installed on your computer&lt;/p&gt;



&lt;p&gt;On the server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express")
const Stream = require("node-rtsp-stream")
const cors = require("cors")

const app = express()
const port = 3002
let stream = null

app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
)

app.get("/stream", (req, res) =&amp;gt; {
  const newRtspStreamUrl = req.query.rtsp
  let currentRtspStreamUrl = ""

  // Create the WebSocket stream only if it doesn't exist or the RTSP URL has changed
  if (!stream || currentRtspStreamUrl !== newRtspStreamUrl) {
    if (stream || newRtspStreamUrl === "stop") {
      stream.stop()
    }
    stream = new Stream({
      name: "Camera Stream",
      streamUrl: newRtspStreamUrl,
      wsPort: 9999,
    })
    currentRtspStreamUrl = newRtspStreamUrl
  }

  res.send(200).json({ url: `ws://127.0.0.1:9999` })
})

app.listen(port, () =&amp;gt; {
  console.log(`Server running on port ${port}`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the client&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 JSMpeg from "@cycjimmy/jsmpeg-player"
import axios from "axios"

const StreamPlayer = () =&amp;gt; {

useEffect(()=&amp;gt;{
    const url = 'ws://127.0.0.1:9999'
    let canvas = document.getElementById("video-canvas")
    new JSMpeg.Player(url, { canvas: canvas })
},[])

const rtspurl = ""//enter the rtsp url here

const httpRequest = (url) =&amp;gt; {
   axios.get(`http://127.0.0.1:3002/stream?rtsp=${url}`)
}

const startRTSPFeed = () =&amp;gt; {
   httpRequest(rtspurl)
}

const stopRTSPFeed = () =&amp;gt; {
   httpRequest("stop")
}

return(
   &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;canvas id="video-canvas"&amp;gt;&amp;lt;/canvas&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;button onClick={startRTSPFeed}&amp;gt;Start RTSP Feed&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={stopRTSPFeed}&amp;gt; Stop RTSP Feed&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
   &amp;lt;/div&amp;gt;
)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do have a lovely day!!&lt;/p&gt;

</description>
      <category>rtsp</category>
      <category>react</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Set Up User Cookies and Connect Google Analytics in Your React App</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Mon, 16 Sep 2024 05:47:18 +0000</pubDate>
      <link>https://dev.to/qobi/how-to-set-up-user-cookies-and-connect-google-analytics-in-your-react-app-2mi5</link>
      <guid>https://dev.to/qobi/how-to-set-up-user-cookies-and-connect-google-analytics-in-your-react-app-2mi5</guid>
      <description>&lt;p&gt;Question: &lt;em&gt;What is this tutorial about?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This tutorial is about setting up user cookies in your web application and connecting it to the Google Analytics platform.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why go through all this stress?&lt;/em&gt;&lt;br&gt;
Because this setup allows you to track how users navigate your application for free.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who is this tutorial for?&lt;/em&gt;&lt;br&gt;
Anyone with a basic knowledge of React and Typescript&lt;/p&gt;

&lt;p&gt;So if you think it's worth the stress, LET'S GET STARTED!!!&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;For those unaware, Google Analytics is a powerful tool that offers a wide range of features for collecting and analyzing data from your web platform. However, the abundance of options can be overwhelming, especially when you first encounter the dashboard and its numerous use cases. One of my favorite applications of Google Analytics is setting up user cookies on my web application and connecting them to the Google Analytics platform. This capability allows you to track how users navigate your application for free. With a little patience and a step-by-step approach, you can easily set this up and gain valuable insights into user behavior.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll walk you through setting up user cookies in your React app and connecting them to Google Analytics. We'll cover how to request user consent for different types of cookies and send this data to Google Analytics using the Global Site Tag (gtag.js).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prerequisites&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Basic knowledge of React.&lt;/li&gt;
&lt;li&gt;
A Google Analytics account. If you don't have one, follow this guide on setting up a Google Analytics account for User consent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Google tag
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Add the Google Tag (gtag.js) to Your HTML
First, add the Google Tag (gtag.js) to your public/index.html file:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Google tag (gtag.js) --&amp;gt;
&amp;lt;script
  async
  src="https://www.googletagmanager.com/gtag/js?id=YOURGOOGLETAG"
&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
  window.dataLayer = window.dataLayer || []
  function gtag() {
    dataLayer.push(arguments)
  }
  gtag('js', new Date())

  gtag('config', 'YOURGOOGLETAG')
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
Extend Global Types with global.d.ts
Create or update the global.d.ts file to extend the global window object, allowing TypeScript to recognize the gtag function:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;declare global {
  interface Window {
    gtag: (
      command: string,
      action: string,
      params?: { [key: string]: any }
    ) =&amp;gt; void
  }
}

export {} // Ensures the file is treated as a module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
Set Up Your tsconfig.json
Ensure your tsconfig.json includes the correct configuration to support the necessary TypeScript features:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;include the global.d.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    ...
  },
  "include": ["src/**/*", ".d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
Create the Consent Banner Component
The ConsentBanner component handles user consent for various types of cookies and communicates this information to Google Analytics:
Use or restyle however you wish
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState, FC } from 'react'
import { getUserCookies, setUserCookies } from '../../../constants/global'

const ConsentBanner: FC = () =&amp;gt; {
  const [isVisible, setIsVisible] = useState&amp;lt;boolean&amp;gt;(false)
  const [showPreferences, setShowPreferences] = useState&amp;lt;boolean&amp;gt;(false)
  const [preferences, setPreferences] = useState&amp;lt;{
    essential: boolean
    analytics: boolean
    userdata: boolean
    personalization: boolean
    marketing: boolean
  }&amp;gt;({
    essential: true,
    analytics: false,
    marketing: false,
    personalization: false,
    userdata: false
  })

  useEffect(() =&amp;gt; {
    const consent = getUserCookies()
    if (!consent) {
      setIsVisible(true)
    }
  }, [])

  const handleAcceptAll = (): void =&amp;gt; {
    setPreferences({
      essential: true,
      analytics: true,
      marketing: true,
      personalization: true,
      userdata: true
    })
    setUserCookies(preferences)
    window.gtag('consent', 'update', {
      ad_storage: 'granted',
      analytics_storage: 'granted',
      ad_user_data: 'granted',
      ad_personalization: 'granted',
      wait_for_update: 500
    })
    setIsVisible(false)
  }

  const handleShowPreferences = (): void =&amp;gt; {
    setShowPreferences(true)
  }

  const handleAcceptPreferences = (): void =&amp;gt; {
    setUserCookies(preferences)
    window.gtag('consent', 'update', {
      ad_storage: preferences.marketing ? 'granted' : 'denied',
      analytics_storage: preferences.analytics ? 'granted' : 'denied',
      ad_user_data: preferences.userdata ? 'granted' : 'denied',
      ad_personalization: preferences.personalization ? 'granted' : 'denied',
      wait_for_update: 500
    })
    setIsVisible(false)
  }

  const handleCheckboxChange = (
    event: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;
  ): void =&amp;gt; {
    const { name, checked } = event.target
    setPreferences((prev) =&amp;gt; ({ ...prev, [name]: checked }))
  }

  if (!isVisible) return null

  return (
    &amp;lt;div style={styles.banner} className="f-column-10 py-4"&amp;gt;
      &amp;lt;p style={styles.text}&amp;gt;
        We use cookies to enhance your experience. Please choose your preferences:
      &amp;lt;/p&amp;gt;
      {showPreferences ? (
        &amp;lt;div
          style={styles.checkboxContainer}
          className="grid-wrapper-45 gap-33 aic py-4"
        &amp;gt;
          &amp;lt;label className="f-row-7"&amp;gt;
            &amp;lt;input
              type="checkbox"
              name="essential"
              checked={preferences.essential}
              readOnly
            /&amp;gt;
            Essential Cookies (required)
          &amp;lt;/label&amp;gt;
          &amp;lt;label className="f-row-7"&amp;gt;
            &amp;lt;input
              type="checkbox"
              name="analytics"
              checked={preferences.analytics}
              onChange={handleCheckboxChange}
            /&amp;gt;
            Analytics Cookies
          &amp;lt;/label&amp;gt;
          &amp;lt;label className="f-row-7"&amp;gt;
            &amp;lt;input
              type="checkbox"
              name="marketing"
              checked={preferences.marketing}
              onChange={handleCheckboxChange}
            /&amp;gt;
            Marketing Cookies
          &amp;lt;/label&amp;gt;
          &amp;lt;label className="f-row-7"&amp;gt;
            &amp;lt;input
              type="checkbox"
              name="personalization"
              checked={preferences.personalization}
              onChange={handleCheckboxChange}
            /&amp;gt;
            Tailored Content Cookies
          &amp;lt;/label&amp;gt;
          &amp;lt;label className="f-row-7"&amp;gt;
            &amp;lt;input
              type="checkbox"
              name="userdata"
              checked={preferences.userdata}
              onChange={handleCheckboxChange}
            /&amp;gt;
            User Data Cookies
          &amp;lt;/label&amp;gt;
        &amp;lt;/div&amp;gt;
      ) : null}
      &amp;lt;div style={styles.buttonContainer}&amp;gt;
        &amp;lt;button
          style={styles.button}
          onClick={handleAcceptAll}
          aria-label="accept all cookies"
        &amp;gt;
          Accept All
        &amp;lt;/button&amp;gt;
        &amp;lt;button
          style={styles.button}
          onClick={handleShowPreferences}
          aria-label="customize cookie preferences"
        &amp;gt;
          Customize Preferences
        &amp;lt;/button&amp;gt;
        {showPreferences &amp;amp;&amp;amp; (
          &amp;lt;button
            style={styles.button}
            onClick={handleAcceptPreferences}
            aria-label="save cookies"
          &amp;gt;
            Save Preferences
          &amp;lt;/button&amp;gt;
        )}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

const styles = {
  banner: {
    position: 'fixed' as 'fixed',
    bottom: '0',
    left: '0',
    right: '0',
    backgroundColor: '#141414',
    color: '#fff',
    padding: '10px',
    textAlign: 'center' as 'center',
    zIndex: 1000
  },
  text: {
    margin: '0 0 10px'
  },
  checkboxContainer: {
    textAlign: 'left' as 'left',
    margin: '10px auto',
    maxWidth: '500px'
  },
  buttonContainer: {
    display: 'flex' as 'flex',
    justifyContent: 'center' as 'center',
    gap: '10px'
  },
  button: {
    backgroundColor: '#007BFF',
    color: '#fff',
    border: 'none',
    padding: '10px 20px',
    cursor: 'pointer',
    borderRadius: '5px'
  }
}

export default ConsentBanner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This tutorial covered setting up user cookies in your React application and connecting them to Google Analytics. Remember, getting consent from users is crucial for compliance with privacy regulations.&lt;/p&gt;

</description>
      <category>cookies</category>
      <category>analytics</category>
      <category>googleanalytics</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Connect a Domain to Cloudflare and a Modern Deployment Platform</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Mon, 16 Sep 2024 05:23:32 +0000</pubDate>
      <link>https://dev.to/qobi/how-to-connect-a-domain-to-cloudflare-and-a-modern-deployment-platform-1lh5</link>
      <guid>https://dev.to/qobi/how-to-connect-a-domain-to-cloudflare-and-a-modern-deployment-platform-1lh5</guid>
      <description>&lt;p&gt;Question: &lt;em&gt;What is this tutorial about?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To learn how to connect a domain name to Cloudflare and then set it up with a web hosting service or deployment platform like Netlify or Vercel.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why go through all this stress?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because it improves your website's security, speed, and ease of management.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Faster Load Times&lt;/li&gt;
&lt;li&gt;
Better Security&lt;/li&gt;
&lt;li&gt;
Almost always available 99.99% (never a downtime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Who is this tutorial for?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anyone with a technical background who has purchased a domain name and is familiar with creating online accounts. If you're new to these processes, don't worry - we'll provide short descriptions and external tutorial links (here and there) to help improve your knowledge of the subject and also guide you through any unfamiliar steps.&lt;/p&gt;

&lt;p&gt;So if you think it's worth the stress, LET'S GET STARTED!!!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prerequisites&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You should have already completed some basic steps or have the following ready:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Domain from Namecheap: You should have already purchased a domain name from a domain registrar like Namecheap. (We'll be making use of Namecheap for this tutorial)&lt;/li&gt;
&lt;li&gt;
Cloudflare Account: You need to have a Cloudflare account setup.&lt;/li&gt;
&lt;li&gt;
Hosting Service Account: You should have an account with a web hosting service or deployment platform, such as Netlify or Vercel. (We'll be making use of Netlify for this tutorial)&lt;/li&gt;
&lt;li&gt;
Basic Understanding of DNS Records: A general idea of what DNS records are and how they function.&lt;/li&gt;
&lt;li&gt;
Access to Your Domain's DNS Settings: You should have access to the DNS settings in both Namecheap and Cloudflare.&lt;/li&gt;
&lt;li&gt;
Web Project Ready for Deployment: A website or web project you want to deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First, Go to your Cloudflare Account
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Add a New Site: Click the "Add a Site" or "Add a domain" button on your Cloudflare dashboard.&lt;/li&gt;
&lt;li&gt;
Enter Your Domain: Input your Namecheap domain and click "Add Site."&lt;/li&gt;
&lt;li&gt;
Select a Plan: Choose a plan that fits your needs (the free plan is usually sufficient).&lt;/li&gt;
&lt;li&gt;
Update DNS Records: Cloudflare will scan and automatically add DNS records for your domain. Delete all the DNS records created automatically. We add ours.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, Update Domain Nameservers in Namecheap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Return to your Namecheap account.
Go to the "Domain List" section and select the domain you want to update.&lt;/li&gt;
&lt;li&gt;
Click on "Manage" next to the domain.&lt;/li&gt;
&lt;li&gt;
Under the "Nameservers" section, select "Custom DNS."&lt;/li&gt;
&lt;li&gt;
Enter Cloudflare Nameservers: Copy the nameservers provided by Cloudflare and paste them into the fields in Namecheap.&lt;/li&gt;
&lt;li&gt;
To find the nameservers in Cloudflare, go to DNS section &amp;gt; Record. &lt;/li&gt;
&lt;li&gt;
Scroll down to the section titled "Cloudflare Nameservers", you'll find the name servers.&lt;/li&gt;
&lt;li&gt;
Save Changes: Click "Save" to apply the changes. It might take some time for DNS propagation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, Deploy Your Web Project on Netlify
&lt;/h2&gt;

&lt;p&gt;Follow this instruction to easily deploy your project to Netlify&lt;br&gt;
Next, Add Your Domain to Netlify&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
In your Netlify dashboard, go to the site you want to connect to your domain.&lt;/li&gt;
&lt;li&gt;
Under Site Settings, click on Domain Management.&lt;/li&gt;
&lt;li&gt;
Click on Add Custom Domain and enter your domain name (e.g., yourdomain.com). &lt;/li&gt;
&lt;li&gt;
The domain name should be the same one you connected to Cloudflare.
Click Verify.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, Configure DNS in Cloudflare
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Go to your Cloudflare account.&lt;/li&gt;
&lt;li&gt;
Select the domain you want to connect to Netlify from the Cloudflare dashboard.&lt;/li&gt;
&lt;li&gt;
Go to the DNS section in Cloudflare and add the following DNS Records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll need to add two main records:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CNAME Record for the www Subdomain&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
Click on Add Record.&lt;/li&gt;
&lt;li&gt;
Choose CNAME as the type.&lt;/li&gt;
&lt;li&gt;
Set Name to &lt;a href="http://www" rel="noopener noreferrer"&gt;www&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
Set Target to your Netlify subdomain (e.g., yoursite.netlify.app).&lt;/li&gt;
&lt;li&gt;
Go to your Netlify account &amp;gt; Doman management &amp;gt; You'll find the Netlify subdomain under the Product Domains section (first row)&lt;/li&gt;
&lt;li&gt;
Click Save.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;A Record for the Root Domain (yourdomain.com)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
Click on Add Record.&lt;/li&gt;
&lt;li&gt;
Choose A as the type.&lt;/li&gt;
&lt;li&gt;
Set Name to @ or leave it blank (depending on Cloudflare's interface).&lt;/li&gt;
&lt;li&gt;
Set IPv4 address to 75.2.60.5 and Click Save.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, Verify the Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Wait for DNS propagation (which can take up to 48 hours, but usually quicker).&lt;/li&gt;
&lt;li&gt;
Visit your domain (yourdomain.com or &lt;a href="http://www.yourdomain.com" rel="noopener noreferrer"&gt;www.yourdomain.com&lt;/a&gt;) and ensure it points to your Netlify site.&lt;/li&gt;
&lt;li&gt;
Check that SSL is working correctly by ensuring the site loads securely (https://).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've done with the setup and everything is working fine, here's what you need to do next:&lt;/p&gt;

&lt;p&gt;Follow this tutorial to set SSL for your custom domain:&lt;br&gt;
How to enable SSL in Netlify with a custom domain&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Check SSL/TLS Settings: Since Netlify handles SSL (security certificates) for your site, make sure Cloudflare's SSL/TLS settings are set to "Full" or "Full (Strict)" to avoid conflicts. This ensures that the connection between Cloudflare and Netlify is secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow this tutorial:&lt;br&gt;
Steps to Set Up Cloudflare CDN and Optimize Your Website&lt;/p&gt;

&lt;p&gt;By following these steps, you'll ensure that Cloudflare works smoothly with Netlify and keeps your site secure and fast.&lt;/p&gt;

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

&lt;p&gt;Once everything is set up, your Cloudflare-managed domain should point to your Netlify site, with SSL provided either by Cloudflare or Netlify, depending on your configuration.&lt;/p&gt;

&lt;p&gt;I hope you found it useful and please ask questions if you need more clarity.&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>deployment</category>
      <category>domain</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to set up and manage a professional email for free</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Mon, 16 Sep 2024 05:07:53 +0000</pubDate>
      <link>https://dev.to/qobi/how-to-set-up-and-manage-a-professional-email-for-free-8n3</link>
      <guid>https://dev.to/qobi/how-to-set-up-and-manage-a-professional-email-for-free-8n3</guid>
      <description>&lt;p&gt;Question: &lt;em&gt;What is this tutorial about?&lt;/em&gt;&lt;br&gt;
This tutorial introduces a practical approach to setting up a custom email address for your online business website for free.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why go through this stress?&lt;/em&gt;&lt;br&gt;
If you're a small business owner, freelancer, or solopreneur, you know how important it is to maintain a professional image, which includes having a custom email address for your business.&lt;br&gt;
However, you might not have the budget for a dedicated email hosting service.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who is this tutorial for?&lt;/em&gt;&lt;br&gt;
This tutorial is for small business owners, freelancers, and solopreneurs who want to set up a professional email address without spending money on dedicated email hosting services.&lt;/p&gt;

&lt;p&gt;So if you think it's worth the stress, LET’S DIVE IN!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Setting up and managing a professional email for your business for free means getting an email address that looks like &lt;a href="mailto:yourname@yourbusiness.com"&gt;yourname@yourbusiness.com&lt;/a&gt; without paying for email hosting services. It helps your business look professional and trustworthy without extra costs.&lt;br&gt;
I'm going to show you how to get it done, but before we proceed you need to understand the pros and cons of the setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Are the Pros and Cons?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pros:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Using a custom email address associated with your domain enhances your professional image.&lt;/li&gt;
&lt;li&gt;
Using Gmail to manage your custom domain email is cheaper than paying for a dedicated email hosting service.&lt;/li&gt;
&lt;li&gt;
You only have to check one email account, and you can manage multiple addresses in a single inbox.&lt;/li&gt;
&lt;li&gt;
Many people are already familiar with Gmail, so there's no learning curve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cons:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Relying on Gmail for business communications can be risky if not properly secured (e.g., two-factor authentication).&lt;/li&gt;
&lt;li&gt;
Using Gmail means you're subject to Google's terms of service and potential changes in their policies.&lt;/li&gt;
&lt;li&gt;
Gmail offers less flexibility in terms of advanced email management and custom features compared to dedicated email hosting solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we understand the risks and the rewards, LETS DIVE IN!!!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are the prerequisites for setting up a free professional email for your business:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
A Domain Name: You need to own a domain name (like yourbusiness.com). You can buy one from domain registrars like Namecheap, GoDaddy, or Google Domains.&lt;/li&gt;
&lt;li&gt;
Gmail Account: A free Gmail account is required to set up your custom email address to receive and send emails through Gmail.&lt;/li&gt;
&lt;li&gt;
Domain Access: You need access to your domain's DNS settings (usually through your domain registrar) to configure email forwarding or connect to Gmail.&lt;/li&gt;
&lt;li&gt;
Basic Understanding of DNS Settings: A general knowledge of how to add or modify DNS records (like MX, TXT, and CNAME records) to ensure your domain is set up correctly for email.&lt;/li&gt;
&lt;li&gt;
Cloudflare (Optional but Recommended): If you're using Cloudflare for your domain management, you'll need an account and access to your domain there. (for this tutorial we'll be making use of cloudflare)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the basic things you need to set up and manage a professional email for free!&lt;/p&gt;

&lt;h2&gt;
  
  
  First, get your Domain Name
&lt;/h2&gt;

&lt;p&gt;A domain name (like yourbusiness.com). If you don't have one yet, you'll need to buy it from a domain registrar like Namecheap, GoDaddy, or Google Domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next, sign up for Cloudflare
&lt;/h2&gt;

&lt;p&gt;If you don't have one, go to Cloudflare's website and sign up for a free account.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Steps:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Go to Cloudflare's website and create an account.&lt;/li&gt;
&lt;li&gt;
Add your domain name to Cloudflare.&lt;/li&gt;
&lt;li&gt;
Cloudflare will automatically provide you with new nameservers. You'll need to update these nameservers with your domain registrar.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, update your Domain's Nameservers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Log in to your domain registrar's website.&lt;/li&gt;
&lt;li&gt;
Find the DNS or Nameserver settings for your domain.&lt;/li&gt;
&lt;li&gt;
Replace the existing nameservers with the ones provided by Cloudflare.&lt;/li&gt;
&lt;li&gt;
Save the changes. It may take a few hours for the changes to take effect.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, set up Email Forwarding with Cloudflare
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Go to your Cloudflare account.&lt;/li&gt;
&lt;li&gt;
Select your domain from the dashboard.&lt;/li&gt;
&lt;li&gt;
Click on the "Email" tab in the Cloudflare dashboard. If you don't see this tab, ensure your domain is fully set up.&lt;/li&gt;
&lt;li&gt;
Click "Email Routing" to start configuring email routing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next, create Email Routes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Click "Create a Route".&lt;/li&gt;
&lt;li&gt;
Enter the email address you want to route in the "Source Email" field (e.g., &lt;a href="mailto:info@yourbusiness.com"&gt;info@yourbusiness.com&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
Enter the destination email address where you want the emails to be forwarded (e.g., your Gmail address).&lt;/li&gt;
&lt;li&gt;
Click "Save".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this setup, any emails sent to your custom email address will land directly in your Gmail inbox.&lt;br&gt;
But we're not done yet….&lt;br&gt;
We still need to set up Gmail to send emails using your custom email address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next, set up Gmail (2-factor auth)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Go to your Gmail account.&lt;/li&gt;
&lt;li&gt;
Click your profile picture (top-right) &amp;gt; Select Manage your Google account.&lt;/li&gt;
&lt;li&gt;
In the navigation panel, select Security.&lt;/li&gt;
&lt;li&gt;
Under the "How you sign in to Google" section, select 2-Step Verification &amp;gt; Get started.&lt;/li&gt;
&lt;li&gt;
Follow the onscreen steps and setup the 2-step verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or follow the tutorial here to set it up&lt;br&gt;
 &lt;a href="https://support.google.com/accounts/answer/185839?hl=en&amp;amp;co=GENIE.Platform%3DDesktop" rel="noopener noreferrer"&gt;https://support.google.com/accounts/answer/185839?hl=en&amp;amp;co=GENIE.Platform%3DDesktop&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next, generate the Gmail App Password
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Go to your Gmail account.&lt;/li&gt;
&lt;li&gt;
Click your profile picture (top-right) &amp;gt; Select Manage your Google account.&lt;/li&gt;
&lt;li&gt;
In the navigation panel, select Security.&lt;/li&gt;
&lt;li&gt;
Under Signing in to Google, select 2-Step Verification.&lt;/li&gt;
&lt;li&gt;
At the bottom of the page, select App Passwords.
&lt;em&gt;You can also access App Passwords directly by clicking this link:
&lt;a href="https://myaccount.google.com/apppasswords" rel="noopener noreferrer"&gt;https://myaccount.google.com/apppasswords&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
Enter the app name, and click the create button.
A new password would be generated, copy the password, and save it in a place where you can easily copy it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lastly, set up your custom email address in Gmail so you can send emails from it.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Go to your Gmail account&lt;/li&gt;
&lt;li&gt;
Click the Settings Icon &amp;gt; See all settings&lt;/li&gt;
&lt;li&gt;
Click the Accounts and Imports tab&lt;/li&gt;
&lt;li&gt;
Look for the section "Send mail as:" and Click Add another email address. A pop-up window titled "Add another email address that you own" will appear.&lt;/li&gt;
&lt;li&gt;
Enter the custom email address you set up for email routing in Cloudflare.&lt;/li&gt;
&lt;li&gt;
Click the "Next Step" button.&lt;/li&gt;
&lt;li&gt;
For the SMTP Server, enter "smtp.gmail.com".&lt;/li&gt;
&lt;li&gt;
Set the Username field to your Gmail address.&lt;/li&gt;
&lt;li&gt;
Paste the password generated from the Google app password section.&lt;/li&gt;
&lt;li&gt;
Click the "Add Account" button, and your custom email will be successfully added to your Gmail account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Open your Gmail account.&lt;/li&gt;
&lt;li&gt;
Click the "Compose" button.&lt;/li&gt;
&lt;li&gt;
Click the "From" field, and a drop-down menu will appear showing your custom and original email addresses.&lt;/li&gt;
&lt;li&gt;
Select your custom email address, compose your message, and send.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congratulations! You can now send and receive emails using your custom email address through Gmail.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Master React Global State with a Custom Hook: Simplify Your App’s State Management</title>
      <dc:creator>frank edekobi</dc:creator>
      <pubDate>Sun, 15 Sep 2024 08:46:05 +0000</pubDate>
      <link>https://dev.to/qobi/master-react-global-state-with-a-custom-hook-simplify-your-apps-state-management-4del</link>
      <guid>https://dev.to/qobi/master-react-global-state-with-a-custom-hook-simplify-your-apps-state-management-4del</guid>
      <description>&lt;p&gt;Question: &lt;em&gt;What is this tutorial about?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This tutorial introduces a practical, custom approach that makes it easier to organize and manage state for small to large or complex React applications using useReducer + React Context.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why go through all this stress?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This approach helps you manage shared state more easily in larger React apps plus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
No Need for Conditional Chaining (?.)&lt;/li&gt;
&lt;li&gt;
Cleaner Code&lt;/li&gt;
&lt;li&gt;
Centralized State Management&lt;/li&gt;
&lt;li&gt;
Easier to Reset or Update State&lt;/li&gt;
&lt;li&gt;
Scalable and Flexible&lt;/li&gt;
&lt;li&gt;
Consistency Across the App&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Who is this tutorial for?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This tutorial is aimed at developers with an intermediate skill level in React and Typescript, who are familiar with basic state management and hooks but want to deepen their knowledge by learning how to implement a custom global state solution using hooks like useReducer and React Context.&lt;/p&gt;

&lt;p&gt;So if you think it's worth the stress, LET’S DIVE IN!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  React Context + useReducer hook
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Let's start with the useReducer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine you have a bunch of data (a “state”) that changes as the user interacts with your app (like filling out a form or choosing different options). You want an organized way to update this data, clear it out, or reset everything back to its starting point.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let’s break it down&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
useReducer: is like a traffic control system for your state. It decides how the state should change based on certain actions you send it (like "Update this part" or "Clear everything").&lt;/li&gt;
&lt;li&gt;
State: The “state” is a collection of values that describe the current situation in your app (like a user’s inputs or choices).&lt;/li&gt;
&lt;li&gt;
Action: An “action” is a signal you send to tell the reducer what to do with the state. For example, “Update the user’s name” or “Clear all data.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Now you’ve gotten the idea, let’s get into the tutorial proper&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tutorial&lt;/p&gt;

&lt;h2&gt;
  
  
  First, Create a state-hook.tsx file.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const reducer = &amp;lt;T extends { [key: string]: any }&amp;gt;(
  initState: T, // The initial state when you start the app
  state: T,     // The current state, as it changes over time
  action: { type: keyof T | 'CLEAR_ALL'; payload?: any } // What should change
) =&amp;gt; {
  switch (action.type) {
    case 'CLEAR_ALL':
      return { ...initState } // Reset everything to the original state

    default:
      if (action.type in state) {
        // Only update if the new value is different
        if (state[action.type] === action.payload) return state 
        return { ...state, [action.type]: action.payload } // Update part of the state
      }
      return state // Return the same state if nothing changes
  }
}

export interface IUSH&amp;lt;T&amp;gt; {
  state: T
  updateState: &amp;lt;A extends keyof T&amp;gt;(type: A, payload: T[A]) =&amp;gt; void // Ensure payload matches the type of the state property
  clearState: &amp;lt;A extends keyof T&amp;gt;(type: A) =&amp;gt; void
  clearAll: () =&amp;gt; void
}

export const useStateHook = &amp;lt;T extends { [key: string]: any }&amp;gt;(
  initState: T // Starting values for the state
): IUSH&amp;lt;T&amp;gt; =&amp;gt; {
  const [state, dispatch] = useReducer(reducer, initState) // This sets up the state system

  // Function to update part of the state
  const updateState = useCallback(
    &amp;lt;A extends keyof T&amp;gt;(type: A, payload: T[A]) =&amp;gt; {
      dispatch({ type, payload }) // Send an action to the reducer to update state
    },
    []
  )

  // Function to reset a specific part of the state
  const clearState = useCallback(&amp;lt;A extends keyof T&amp;gt;(type: A) =&amp;gt; {
    dispatch({ type, payload: initState[type] }) // Reset to the initial value for that part
  }, [])

  // Function to clear everything (reset all state)
  const clearAll = useCallback(() =&amp;gt; {
    dispatch({ type: 'CLEAR_ALL' }) // Clear the entire state
  }, [])

  return { state, updateState, clearState, clearAll } // Return the state and the functions
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reducer function is the brain behind the state updates. It checks what action has been sent and changes the state accordingly.&lt;/p&gt;

&lt;p&gt;The useStateHook function is a custom hook you would use in your app. It helps you manage the state with three main functions: updateState, clearState, clearAll&lt;/p&gt;

&lt;h2&gt;
  
  
  Next, create a component-state.ts file
&lt;/h2&gt;

&lt;p&gt;Define the interface IComponentState and the object initComponentState&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IComponentState {
// define your state here
}

export const initComponentState: IComponentState = {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next, add the useStateHook to your Layout file
&lt;/h2&gt;

&lt;p&gt;If you do not have a layout file add it to the file that defines the general structure of your web application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of a layout file structure&lt;/em&gt;&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 { Outlet, Link } from 'react-router-dom'; // Used with react-router for navigation

const Layout = ({ children }) =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      {/* Header */}
      &amp;lt;header&amp;gt;
        &amp;lt;nav&amp;gt;
          &amp;lt;ul&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;Link to="/"&amp;gt;Home&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;Link to="/about"&amp;gt;About&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;Link to="/contact"&amp;gt;Contact&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;/ul&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/header&amp;gt;

      {/* Main content (this changes based on the page) */}
      &amp;lt;main&amp;gt;
        {children} {/* This renders the nested content */}
        or 
        &amp;lt;Outlet /&amp;gt; {/* This renders the specific page/component content */}
      &amp;lt;/main&amp;gt;

      {/* Footer */}
      &amp;lt;footer&amp;gt;
        &amp;lt;p&amp;gt;&amp;amp;copy; 2024 My Website&amp;lt;/p&amp;gt;
      &amp;lt;/footer&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Layout;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add the useStateHook before the return statement
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Assuming the IComponentState and initComponentState are defined
const global = useStateHook&amp;lt;IComponentState&amp;gt;(initComponentState);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next, create a context.ts file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useContext } from 'react';

// Define the type for your context
interface IGlobalContext {
  global: IUSH&amp;lt;IComponentState&amp;gt;
}

// Create the context with an initial value
export const GlobalContext = createContext&amp;lt;IGlobalContext&amp;gt;({
  global: {
    state: initComponentState,
    updateState: () =&amp;gt; {},
    clearState: () =&amp;gt; {},
    clearAll: () =&amp;gt; {}
  }
});

// Custom hook to use the GlobalContext
export const useGlobalContext = () =&amp;gt; {
  const context = useContext(GlobalContext);
  if (!context) {
    throw new Error('useGlobalContext must be used within a GlobalProvider');
  }
  return context;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next, Modify the layout file
&lt;/h2&gt;

&lt;p&gt;Now, in the layout file, you can wrap the children with the GlobalContext.Provider so that the state is available throughout the app:&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 { useStateHook } from './useStateHook'; // Assuming this is your custom hook
import { GlobalContext } from './GlobalContext'; // Context created earlier

const initComponentState = {
  // define the initial state here
};

const Layout: React.FC = ({ children }) =&amp;gt; {
  const global = useStateHook&amp;lt;IComponentState&amp;gt;(initComponentState); // Initialize global state

  return (
    &amp;lt;GlobalContext.Provider value={{global}}&amp;gt;
      &amp;lt;div&amp;gt;
        {/* Header */}
        &amp;lt;header&amp;gt;
          &amp;lt;nav&amp;gt;
            &amp;lt;ul&amp;gt;
              &amp;lt;li&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
              &amp;lt;li&amp;gt;&amp;lt;a href="/about"&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
          &amp;lt;/nav&amp;gt;
        &amp;lt;/header&amp;gt;

        {/* Main content */}
        &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;

        {/* Footer */}
        &amp;lt;footer&amp;gt;
          &amp;lt;p&amp;gt;&amp;amp;copy; 2024 My Website&amp;lt;/p&amp;gt;
        &amp;lt;/footer&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/GlobalContext.Provider&amp;gt;
  );
};

export default Layout;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations!!!, we’re done with the setup.&lt;/p&gt;

&lt;p&gt;Now let’s test it to see if it works as advertised&lt;/p&gt;

&lt;h2&gt;
  
  
  First, modify the component-state.ts file
&lt;/h2&gt;

&lt;p&gt;We’ll add some states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IComponentState {
// define your state here
    name: string
    occupation: string
}

export const initComponentState: IComponentState = {
   name: "",
   occupation: ""
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next, Create a Child Component.tsx and Access the Global State in it
&lt;/h2&gt;

&lt;p&gt;Now, any child component wrapped inside the Layout can use the useGlobalContext hook to access and manipulate the global state.&lt;/p&gt;

&lt;p&gt;Here’s how a child component can use the global state:&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 { useGlobalContext } from './GlobalContext';

const ChildComponent: React.FC = () =&amp;gt; {
  const { global } = useGlobalContext();
  const { state, updateState, clearState, clearAll } = global;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Global State Example&amp;lt;/h1&amp;gt;
      &amp;lt;pre&amp;gt;{JSON.stringify(state)}&amp;lt;/pre&amp;gt;

      {/* Example: Update a part of the global state */}
      &amp;lt;button
        onClick={() =&amp;gt; updateState('name', 'Franklyn Edekobi')}
      &amp;gt;
        Update Name
      &amp;lt;/button&amp;gt;

      &amp;lt;button
        onClick={() =&amp;gt; updateState('occupation', 'Software Engineer')}
      &amp;gt;
        Update Occupation
      &amp;lt;/button&amp;gt;

      {/* Example: Clear a part of the global state */}
      &amp;lt;button onClick={() =&amp;gt; clearState('name')}&amp;gt;Clear State&amp;lt;/button&amp;gt;

      {/* Example: Clear all global state */}
      &amp;lt;button onClick={clearAll}&amp;gt;Clear All&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ChildComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary of Steps:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
useStateHook: This manages the global state.&lt;/li&gt;
&lt;li&gt;
Context (GlobalContext): Created to provide the global state to all components.&lt;/li&gt;
&lt;li&gt;
Layout: Wraps children with GlobalContext.Provider to make the state accessible globally.&lt;/li&gt;
&lt;li&gt;
Child components: Use useGlobalContext to access and update the global state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By structuring it this way, you have a clean and scalable way to manage global state in your React app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;This setup with initComponentState and React Context has several benefits, especially when managing global state across an app. I'll break it down step by step, explaining it in a way that's easy to understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is initComponentState?&lt;/strong&gt;&lt;br&gt;
initComponentState is the initial state of your global state. It’s like having a starting point or default values for everything your app needs. By having these defaults, you don’t need to worry about checking if something is undefined before using it, which can save you from errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of the Problem It Solves&lt;/strong&gt;&lt;br&gt;
Let’s say your app has a part of the global state user that stores the user’s name. Without the initial state, the global state might look like this when no one is logged in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "user": undefined
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means you’d have to write code that checks if user exists before you can use it, 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;console.log(user?.name); // If 'user' is undefined, this won't crash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But with initComponentState, you make sure that user always exists, even if it's empty. So your initial state might 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;{
  "user": {
    "name": ""
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can confidently access user.name without worrying about checking if user exists first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of This Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No Need for Conditional Chaining&lt;/strong&gt; (?.)&lt;/p&gt;

&lt;p&gt;Because initComponentState ensures that every part of your global state has an initial value, you don't have to use tricky checks like user?.name to avoid errors. The initial state gives you confidence that user (or any other part of the state) will always be defined, so you can access it directly without worrying about things breaking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By using this setup, you write cleaner and more readable code. You don’t need to sprinkle your code with checks to see if things are undefined or null. This makes your code easier to maintain and understand.&lt;/p&gt;

&lt;p&gt;Instead of writing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (user?.name) {
  console.log(user.name);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can just do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(user.name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s simpler and more straightforward!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralized State Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This setup makes managing the state across your app easy and centralized. Since the state is shared through the React Context (using the GlobalContext), you don’t need to pass down the state manually through every component. Instead, any component wrapped in the Layout can access the global state using a simple hook (useGlobalContext).&lt;/p&gt;

&lt;p&gt;For example, without global state, you’d have to pass data from parent to child components 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;&amp;lt;ParentComponent&amp;gt;
  &amp;lt;ChildComponent user={user} /&amp;gt;
&amp;lt;/ParentComponent&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, you don’t need to pass user as a prop anymore. The child can just use the global state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { state } = useGlobalContext();
console.log(state.user.name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces the complexity and effort of passing state manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easier to Reset or Update State:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the useStateHook setup, you can easily reset the state or update specific parts without affecting other parts. For example:&lt;/p&gt;

&lt;p&gt;You can clear a specific part of the state (like resetting user).&lt;br&gt;
You can clear the entire state back to its initial values (using clearAll).&lt;br&gt;
This kind of control makes it easy to handle scenarios like logging out a user (clearing user data) or resetting the entire form without losing other data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalable and Flexible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This setup is scalable, meaning it can grow with your app. Whether your app is small or large, this method can handle more complex state structures as your app evolves. You don’t need to rewrite everything when your state becomes bigger or more complicated.&lt;/p&gt;

&lt;p&gt;For example, if you add more features (like managing settings or preferences), you can easily expand the global state without much hassle. The flexibility of this approach means you can keep adding to the state without breaking existing functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency Across the App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By having a well-defined initComponentState, you maintain consistent state structure across your app. Every component that uses the global state will have access to the same structure, which reduces bugs and makes debugging easier.&lt;/p&gt;

&lt;p&gt;For example, every component knows exactly what the state looks like, so there’s no confusion about what data is available or what format it’s in.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No Conditional Chaining:&lt;/strong&gt;&lt;br&gt;
You avoid ?. checks because every part of the state has a default value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner Code:&lt;/strong&gt; &lt;br&gt;
Your code becomes simpler and easier to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralized State:&lt;/strong&gt;&lt;br&gt;
All components have easy access to global state without needing to pass it manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexible and Scalable:&lt;/strong&gt;&lt;br&gt;
The setup can grow with your app as it becomes more complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt;&lt;br&gt;
Ensures that your state is predictable and easy to manage across the whole app.&lt;/p&gt;

&lt;p&gt;This setup simplifies how you manage state in React, making your app more reliable and easier to work on.&lt;/p&gt;

&lt;p&gt;I hope you find this useful. Do have a wonderful day&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
