<?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: Prince De Mawo</title>
    <description>The latest articles on Forem by Prince De Mawo (@demawo).</description>
    <link>https://forem.com/demawo</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%2F865249%2Fc4eb9c2e-1447-4277-bf39-3c39062bc80d.jpeg</url>
      <title>Forem: Prince De Mawo</title>
      <link>https://forem.com/demawo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/demawo"/>
    <language>en</language>
    <item>
      <title>How to Get user location &amp; address autocompletion in React</title>
      <dc:creator>Prince De Mawo</dc:creator>
      <pubDate>Tue, 13 Jun 2023 06:55:21 +0000</pubDate>
      <link>https://forem.com/demawo/how-to-get-user-location-effortless-address-autocompletion-in-react-enhancing-user-experience-595n</link>
      <guid>https://forem.com/demawo/how-to-get-user-location-effortless-address-autocompletion-in-react-enhancing-user-experience-595n</guid>
      <description>&lt;p&gt;One of the key aspects of creating web apps is ensuring a great user experience. However, manually filling out forms for example on the checkout page of an ecommerce website, including entering delivery addresses, can be tedious. In this tutorial, we will explore a solution that allows users to autocomplete their delivery addresses by typing a few characters.&lt;/p&gt;

&lt;p&gt;Demo App: &lt;a href="https://geocoding-kappa.vercel.app/"&gt;App Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;p&gt;. Basic knowledge of JavaScript&lt;br&gt;
. A Mapbox account&lt;br&gt;
. Basic knowledge of React&lt;br&gt;
. Familiarity with Tailwind CSS&lt;br&gt;
. Familiarity with Next.js App Router (easy to follow through, don't worry)&lt;/p&gt;

&lt;p&gt;Let's dive into the implementation:&lt;/p&gt;

&lt;p&gt;Open your terminal and navigate to the directory where you want to create the tutorial folder. For beginners, you can use the command &lt;br&gt;
&lt;code&gt;cd Desktop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Clone the repository: &lt;code&gt;git clone https://github.com/de-mawo/geocoding.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once the files are downloaded, navigate to the geocoding directory: &lt;code&gt;cd geocoding&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Use the git checkout command to switch to the appropriate branch based on your preference:&lt;/p&gt;

&lt;p&gt;For TypeScript users: &lt;code&gt;git checkout ts-starter&lt;/code&gt;&lt;br&gt;
For JavaScript users: &lt;code&gt;git checkout js-starter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you are using VSCode, you can simply type &lt;code&gt;code .&lt;/code&gt; in the terminal to open the current folder in the VSCode IDE.&lt;/p&gt;

&lt;p&gt;Here is the folder structure you should see if you chose &lt;code&gt;ts-starter&lt;/code&gt; branch like me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B0pCRaYh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8b8w1vgd1vksvt60v3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B0pCRaYh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8b8w1vgd1vksvt60v3i.png" alt="Folder structure" width="800" height="386"&gt;&lt;/a&gt;&lt;br&gt;
If you chose the js-starter repository, your file extensions will end with .js instead of .tsx.&lt;/p&gt;

&lt;p&gt;In your terminal, run yarn to install all dependencies. Then, run yarn dev to start the development server. Open your browser and go to localhost:3000 to see a basic navbar. &lt;/p&gt;

&lt;p&gt;If you haven't already, please create a Mapbox account by visiting &lt;a href="https://account.mapbox.com/auth/signup/"&gt;https://account.mapbox.com/auth/signup/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After creating the account, proceed to the Dashboard and generate an access token. This token will be used in our endpoints, as demonstrated below.&lt;/p&gt;

&lt;p&gt;Once the token is generated, you can view its value and copy it. You also have the option to edit the token. To do so, click on "edit" and add &lt;a href="http://localhost:3000/"&gt;http://localhost:3000/&lt;/a&gt; as one of the URLs under the "URLs" section. When you deploy your app, remember to add another production URL.&lt;/p&gt;

&lt;p&gt;Now that you have an access token, create a file named .env at the root level of your folder and include your token in it, like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;REACT_APP_MAPBOX_TOKEN=pk.ejfadhssxxxxxxxxxxxxxxx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's start coding by focusing on the LocationSearchForm component. Edit the component and update it to 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;"use client"
import { ChangeEvent, useEffect, useState } from "react";
import { HiMapPin, HiOutlinePencil } from "react-icons/hi2";
import { toast } from "react-hot-toast";

const LocationSearchForm = () =&amp;gt; {
  const [isEditing, setIsEditing] = useState&amp;lt;boolean&amp;gt;(false);

  const [location, setLocation] = useState&amp;lt;{
    latitude: number;
    longitude: number;
  } | null&amp;gt;(null);

  const [query, setQuery] = useState("");
  const [suggestions, setSuggestions] = useState&amp;lt;Array&amp;lt;{ place_name: string }&amp;gt;&amp;gt;(
    []
  );

  // const checknavigator = navigator.permissions
  // console.log(checknavigator);

  /* Reverse geocoding */
  /* Get User Location on page load and if granted permission by User */
  useEffect(() =&amp;gt; {
    const askForLocationPermission = () =&amp;gt; {
      navigator.geolocation.getCurrentPosition(
        (position) =&amp;gt; {
          const { latitude, longitude } = position.coords;
          setLocation((prevLocation) =&amp;gt; ({
            ...prevLocation,
            latitude,
            longitude,
          }));
        },
        (error) =&amp;gt; {
          // Handle location access denied or error
          toast.error("Error getting location:");
          console.log(error);
        }
      );
    };

    // Check if geolocation is supported by the browser
    if ("geolocation" in navigator) {
      // Ask for permission
      navigator.permissions
        .query({ name: "geolocation" })
        .then((result) =&amp;gt; {
          if (result.state === "granted") {
            // Permission already granted
            askForLocationPermission();
          } else if (result.state === "prompt") {
            // Permission not yet granted, ask the user
            askForLocationPermission();
          } else if (result.state === "denied") {
            // Permission denied, handle accordingly
            toast.error("Location access denied by the user."{ duration: 1000});
          }
        })
        .catch((error) =&amp;gt; {
          // Handle error
          console.error("Error checking location permission:", error);
        });
    } else {
      // Geolocation is not supported
      toast.error("Geolocation is not supported by this browser."{ duration: 1000});
    }
  }, []);

  // Set location and save on local storage based on User granting location permission
  useEffect(() =&amp;gt; {
    if (location) {
      // search for place name using mapbox API    
      const endpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${location.longitude},${location.latitude}.json?proximity=-33.9249,18.4241&amp;amp;country=ZA&amp;amp;access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`;

      fetch(endpoint)
        .then((response) =&amp;gt; response.json())
        .then((data) =&amp;gt; {
          const place = data.features[0].place_name;
          localStorage.setItem("delivery_address", place);
          setQuery(place);
        });
    }
  }, [location]);

  /*Forward geocoding */
  /* Look for location name being queried by user */
  const handleChange = async (event: ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; {
    try {
      setQuery(event.target.value);
      const endpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${event.target.value}.json?proximity=-33.9249,18.4241&amp;amp;country=ZA&amp;amp;access_token=${process.env.REACT_APP_MAPBOX_TOKEN}&amp;amp;autocomplete=true`;

      const response = await fetch(endpoint);
      const results = await response.json();
      // console.log(results);
      setSuggestions(results?.features);
      //  console.log(suggestions);
    } catch (error: any) {
      console.log("Error fetching data: " + error.message);
    }
  };

  /* Display location selected by User  */
  const handleSelectAddress = (selectedAddress: string) =&amp;gt; {
    localStorage.setItem("delivery_address", selectedAddress);
    setQuery(selectedAddress);
    setSuggestions([]);
    setIsEditing(false);
  };

  return (
    &amp;lt;div className="mx-8 md:mx-12 mt-12"&amp;gt;
      &amp;lt;form className="max-w-6xl mx-auto "&amp;gt;
        &amp;lt;div className="relative"&amp;gt;
          {isEditing ? (
            &amp;lt;&amp;gt;
              &amp;lt;div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none"&amp;gt;
                &amp;lt;HiMapPin
                  aria-hidden="true"
                  className="w-5 h-5 text-gray-700 "
                /&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;input
                type="search"
                className="block w-full p-4 pl-10 text-sm text-gray-900 rounded-lg bg-gray-200 outline-none"
                placeholder="Enter your address"
                value={query}
                onChange={handleChange}
              /&amp;gt;
            &amp;lt;/&amp;gt;
          ) : (
            &amp;lt;div className="flex flex-col " onClick={() =&amp;gt; setIsEditing(true)}&amp;gt;
              &amp;lt;p className=""&amp;gt;{query}&amp;lt;/p&amp;gt;
              &amp;lt;button className="px-4 py-1 mt-2 w-24  inline-flex items-center text-green-600 bg-green-200 hover:bg-green-300 border border-green-500 focus-visible:ring-2 rounded-full  "&amp;gt;
                &amp;lt;HiOutlinePencil
                  className="mr-1 -ml-1 w-4 h-4"
                  fill="currentColor"
                /&amp;gt;
                Edit
              &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
          )}
          {suggestions?.length &amp;gt; 0 &amp;amp;&amp;amp; (
            &amp;lt;div className="absolute bg-gray-100 w-full shadow-sm"&amp;gt;
              {suggestions.map((suggestion, index) =&amp;gt; (
                &amp;lt;div
                  key={index}
                  className="flex items-center justify-between w-full p-1 cursor-pointer hover:bg-gray-200"
                  onClick={() =&amp;gt; handleSelectAddress(suggestion.place_name)}
                &amp;gt;
                  {suggestion.place_name}
                &amp;lt;/div&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;This code snippet is a React component for a location search form. It provides an input field where users can search for a location. The form utilizes the Mapbox Geocoding API to provide autocomplete suggestions based on the user's input.&lt;/p&gt;

&lt;p&gt;Our endpoint supports both required and optional parameters. You can find detailed information about these parameters at &lt;a href="https://docs.mapbox.com/api/search/geocoding/"&gt;mapbox signup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For optional parameters, I have included "proximity" to specify the default search area. This allows you to search within a specific proximity. Additionally, I have localized the country for my searches. You can refer to the country codes at &lt;a href="https://www.iso.org/obp/ui/#search"&gt;country codes&lt;/a&gt; for more information on selecting the appropriate country code.&lt;/p&gt;

&lt;p&gt;The component uses the following state variables:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;isEditing&lt;/code&gt;: A boolean variable to track whether the user is editing the location input or not.&lt;br&gt;
&lt;code&gt;location&lt;/code&gt;: A nullable object that holds the latitude and longitude of the user's current location. This information is retrieved using the Geolocation API.&lt;br&gt;
&lt;code&gt;query&lt;/code&gt;: The current value of the location input field.&lt;br&gt;
&lt;code&gt;suggestions&lt;/code&gt;: An array of location suggestions based on the user's input.&lt;br&gt;
The component consists of two useEffect hooks:&lt;/p&gt;

&lt;p&gt;The first &lt;code&gt;useEffect&lt;/code&gt; hook runs once when the component mounts and checks for Geolocation API support. If supported, it asks for the user's location permission. If granted, it sets the &lt;code&gt;location&lt;/code&gt; state with the latitude and longitude of the user's current location. If the permission is denied, an error message is shown.&lt;/p&gt;

&lt;p&gt;The second &lt;code&gt;useEffect&lt;/code&gt; hook runs whenever the &lt;code&gt;location&lt;/code&gt; state changes. It makes a request to the Mapbox Geocoding API to retrieve the place name of the user's current location. The place name is then stored in local storage and set as the initial value of the location input field.&lt;/p&gt;

&lt;p&gt;The component also includes a &lt;code&gt;handleChange&lt;/code&gt; function that is triggered when the user types in the location input field. This function sends a request to the Mapbox Geocoding API with the user's input to fetch autocomplete suggestions. The suggestions are stored in the suggestions state.&lt;/p&gt;

&lt;p&gt;When the user selects a suggested address, the &lt;code&gt;handleSelectAddress&lt;/code&gt; function is called. It stores the selected address in local storage, sets it as the value of the location input field, clears the suggestions, and sets &lt;code&gt;isEditing&lt;/code&gt; to false.&lt;/p&gt;

&lt;p&gt;The JSX code renders the location search form, including the input field, suggestions dropdown (if there are suggestions).&lt;/p&gt;

&lt;p&gt;Overall, this component provides a user-friendly location search form with autocomplete suggestions and the ability to detect the user's current location.&lt;/p&gt;

&lt;p&gt;Now let's also update our LocationBtn component to include the following complete code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { Fragment, useState } from "react";
import {  HiMapPin } from "react-icons/hi2";
import { FaChevronRight } from "react-icons/fa";
import { Dialog, Transition } from "@headlessui/react";
import LocationSearchForm from "./LocationSearchForm";

const LocationBtn = () =&amp;gt; {
  const [isOpen, setIsOpen] = useState(false);
  const [showChange, setShowChange] = useState(false);
  const deliveryAddress  =   typeof window !== "undefined" &amp;amp;&amp;amp; localStorage?.getItem("delivery_address");


  const openModal = () =&amp;gt; setIsOpen(true);
  const closeModal = () =&amp;gt; {
    setShowChange(false);
    setIsOpen(false);
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;button
        onClick={openModal}
        className={`flex items-center px-4 py-2 bg-slate-200 rounded-full md:max-w-sm  md:rounded-lg`}
      &amp;gt;
        {" "}
        &amp;lt;HiMapPin className="shrink-0 text-green-600" /&amp;gt;{" "}
        &amp;lt;span className="h-2 w-2 mx-2 bg-gray-600 shrink-0 rounded-full hidden md:block "&amp;gt;
          {" "}
        &amp;lt;/span&amp;gt;{" "}
        &amp;lt;span
          className={
            "truncate max-w-[8rem]  text-sm text-gray-500 md:max-w-[12rem]"
          }
        &amp;gt;
          {deliveryAddress  ? deliveryAddress  : "Enter Delivery Address"}
        &amp;lt;/span&amp;gt;
        &amp;lt;FaChevronRight className=" shrink-0 text-green-600" /&amp;gt;
      &amp;lt;/button&amp;gt;

      &amp;lt;Transition appear show={isOpen} as={Fragment}&amp;gt;
        &amp;lt;Dialog as="div" className="relative z-10" onClose={closeModal}&amp;gt;
          &amp;lt;Transition.Child
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          &amp;gt;
            &amp;lt;div className="fixed inset-0 bg-black bg-opacity-25" /&amp;gt;
          &amp;lt;/Transition.Child&amp;gt;

          &amp;lt;div className="fixed inset-0 overflow-y-auto"&amp;gt;
            &amp;lt;div className="flex min-h-full items-center justify-center p-4 text-center"&amp;gt;
              &amp;lt;Transition.Child
                as={Fragment}
                enter="ease-out duration-300"
                enterFrom="opacity-0 scale-95"
                enterTo="opacity-100 scale-100"
                leave="ease-in duration-200"
                leaveFrom="opacity-100 scale-100"
                leaveTo="opacity-0 scale-95"
              &amp;gt;
                &amp;lt;Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all"&amp;gt;
                  &amp;lt;Dialog.Title
                    as="h3"
                    className="text-lg font-medium leading-6 text-gray-900"
                  &amp;gt;
                    Delivery Address
                  &amp;lt;/Dialog.Title&amp;gt;

                  {showChange ? (
                    &amp;lt;div className="mt-2"&amp;gt;
                      &amp;lt;LocationSearchForm /&amp;gt;
                    &amp;lt;/div&amp;gt;
                  ) : (
                    &amp;lt;div className="flex items-center mt-8 justify-between"&amp;gt;
                      &amp;lt;div&amp;gt;
                        &amp;lt;p className="truncate max-w-[10rem] md:max-w-xs"&amp;gt;
                          {deliveryAddress 
                            ? deliveryAddress 
                            : "Click change..."}
                        &amp;lt;/p&amp;gt;{" "}
                      &amp;lt;/div&amp;gt;

                      &amp;lt;div&amp;gt;
                        {" "}
                        &amp;lt;button
                          className="px-4 py-1 text-slate-600 bg-green-100 hover:bg-green-200 border border-green-500  rounded-full"
                          onClick={() =&amp;gt; setShowChange(true)}
                        &amp;gt;
                          Change
                        &amp;lt;/button&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  )}

                  &amp;lt;div className="mt-12 mx-12"&amp;gt;
                    &amp;lt;button
                      type="submit"
                      className="px-4 py-1 w-full text-white bg-green-600 hover:bg-green-500 border border-green-600  rounded-full"
                      onClick={closeModal}
                    &amp;gt;
                      Done
                    &amp;lt;/button&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/Dialog.Panel&amp;gt;
              &amp;lt;/Transition.Child&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/Dialog&amp;gt;
      &amp;lt;/Transition&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;LocationBtn&lt;/code&gt; component is a button that displays the delivery address. It includes a modal dialog that allows the user to change the address. The address is retrieved from the browser's local storage and displayed in the button. If no address is available, a placeholder text is shown. Clicking on the button opens the modal dialog where the user can either view the current address or change it using a LocationSearchForm component. After making any changes, the user can click the "Done" button to close the dialog.&lt;/p&gt;

&lt;p&gt;Great! Now let's move on to testing. If you click on the button, you should see a map pin in your browser's address bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U5gUHh1F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbg1u7ko62r8cv0323c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U5gUHh1F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbg1u7ko62r8cv0323c0.png" alt="localhost demo" width="800" height="306"&gt;&lt;/a&gt;&lt;br&gt;
Additionally, you should be able to edit the address and select an auto-completed option.&lt;/p&gt;

&lt;p&gt;Please note that the location permission popup may not appear on localhost. However, once you deploy your app and update the URL permissions in your Mapbox access tokens, everything should work fine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yDP_Z0mb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4hee0u9hgybfqjfs8ak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yDP_Z0mb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4hee0u9hgybfqjfs8ak.png" alt="Production image" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By clicking on the cart, you will be redirected to the /cart route where you can find the LocationBtn once again. This allows you to easily change the address displayed. This user experience eliminates the need for manual address typing, providing convenience for users.&lt;/p&gt;

&lt;p&gt;Thank you for reading through. Watch a tutorial  &lt;a href="https://www.youtube.com/watch?v=bzVehaBkcWo"&gt;video&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mapbox</category>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Logout of Multiple Tabs | React Web App</title>
      <dc:creator>Prince De Mawo</dc:creator>
      <pubDate>Fri, 20 May 2022 12:01:46 +0000</pubDate>
      <link>https://forem.com/demawo/how-to-logout-of-multiple-tabs-react-web-app-2egf</link>
      <guid>https://forem.com/demawo/how-to-logout-of-multiple-tabs-react-web-app-2egf</guid>
      <description>&lt;p&gt;In a real world scenario , you would want users who visit your site to have a great user experience . Security , on the other hand, is of prime importance to users and a secure web app improves user-trust which has a positive effect towards “good business”. A common use behavior of users on websites that require authentication, is opening of multiple tabs as they browse or make transactions. In such a situation, you would like users to be able to sign in and sign out successfully without worrying about whether they are logged out of all tabs or not.&lt;/p&gt;

&lt;p&gt;One of the ways to improve user experience in such a scenario is to make sure that when a user signs out of any tab of your website ,they are logged out of all other tabs once. Thereafter, sensitive data should be removed from the screen by redirecting the user to a public page  and possibly clearing JWT tokens from local Storage.&lt;/p&gt;

&lt;p&gt;I have implemented a simple beginner friendly example of this kind of feature. Let us go ahead and see how I did it. Go on this &lt;strong&gt;&lt;a href="https://github.com/de-mawo/react-dash-v1" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/strong&gt; and download or clone the starter project into a directory of your choice on your local machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fp221t5yhidmaan5hk331.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fp221t5yhidmaan5hk331.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
After cloning the starter project, you should have a structure as below. Run &lt;strong&gt;npm install&lt;/strong&gt; to install the dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsttji9an3sctx9lcp3wz.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsttji9an3sctx9lcp3wz.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead in your terminal a install this dependency &lt;code&gt;npm i broadcast-channel&lt;/code&gt;&lt;br&gt;
To learn more about Broadcast Channel API , I encourage you to go on the following links:&lt;br&gt;
[&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API&lt;/a&gt;]&lt;br&gt;
[&lt;a href="https://github.com/pubkey/broadcast-channel" rel="noopener noreferrer"&gt;https://github.com/pubkey/broadcast-channel&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Once you are done installing the broadcast-channel dependency, run &lt;strong&gt;npm start&lt;/strong&gt; in your terminal to start your application. Your application should now be running on port 3000 or any port you may have configured. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fuofrtt0a02z4sapuaj3q.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuofrtt0a02z4sapuaj3q.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and click the sign in button and you will directed to the dashboard. As a test, duplicate the current tab into 3 or for 4 tabs then go back to the first tab and click sign out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fku9xlzh1cwpxigcdzvia.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fku9xlzh1cwpxigcdzvia.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
As you can see, you are directed to the sign in page on this first tab but the other tabs are still logged in (not good user experience right?). To solve this issue , we will add a few lines of code into the auth.js file inside the auth folder. &lt;/p&gt;

&lt;p&gt;Replace the existing code in your auth.js file with the below code and save;&lt;/p&gt;

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

import history from 'history/browser'
import { BroadcastChannel } from 'broadcast-channel';

const logoutChannel = new BroadcastChannel('logout');

export const login = () =&amp;gt; {
    localStorage.setItem("token", "this_is_a_demo_token")
    history.push('/app/dashboard')
}

export const checkToken = () =&amp;gt; {
    const token = localStorage.getItem("token", 'this_is_a_demo_token' )
    if(!token) return alert('You are not logged in')
    return token

}

export const logout = () =&amp;gt; {
    logoutChannel.postMessage("Logout")
    localStorage.removeItem("token", 'this_is_a_demo_token' )
    window.location.href = window.location.origin + "/";

}

export const logoutAllTabs = () =&amp;gt; {
    logoutChannel.onmessage = () =&amp;gt; {
        logout();
        logoutChannel.close();


    }
}


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

&lt;/div&gt;

&lt;p&gt;So what we did here was to import the broadcast channel module and we created an instance , &lt;em&gt;logoutChannel&lt;/em&gt;, and it "logout". Whenever we sign out ,  a message "Logout" is sent to other  tabs on the same host and port ( host is your local machine and port 3000). &lt;br&gt;
Furthermore , replace the existing code in your App.js file with the code below  and save;&lt;/p&gt;

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

import React, { useEffect } from "react";
import { logoutAllTabs } from "./auth/auth";
import Router from "./routes";


function App() {
useEffect(() =&amp;gt; {
 logoutAllTabs()
}, [])


  return (
    &amp;lt;&amp;gt;

     &amp;lt;Router/&amp;gt;

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

export default App;



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

&lt;/div&gt;

&lt;p&gt;Now lets start again, close all the other tabs and leave  one on the sign in page, click sign in and get directed to the dashboard. Duplicate the current tab into 3 more tabs. At this stage if you sign out from one of the pages, all other open tabs should be logged out as well at the same time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6hbmhtcumt1tp781uvn6.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6hbmhtcumt1tp781uvn6.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all folks!. You are now able to implement this in your own React application as well. If you find the tutorial useful please kindly give me a star on GitHub or follow me on twitter &lt;a href="https://twitter.com/de_mawo" rel="noopener noreferrer"&gt;https://twitter.com/de_mawo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>broadcastchannel</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
