<?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: Ikem O</title>
    <description>The latest articles on Forem by Ikem O (@ikemcodedit).</description>
    <link>https://forem.com/ikemcodedit</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%2F1892255%2Fe2efb13c-6107-46a3-aeba-81669efb98dc.jpg</url>
      <title>Forem: Ikem O</title>
      <link>https://forem.com/ikemcodedit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ikemcodedit"/>
    <language>en</language>
    <item>
      <title>Upskilling In Tech (The 1 Hour Rule)</title>
      <dc:creator>Ikem O</dc:creator>
      <pubDate>Tue, 01 Apr 2025 23:08:40 +0000</pubDate>
      <link>https://forem.com/ikemcodedit/upskilling-in-tech-the-1-hour-rule-5099</link>
      <guid>https://forem.com/ikemcodedit/upskilling-in-tech-the-1-hour-rule-5099</guid>
      <description>&lt;p&gt;I’ve been in the tech space for three years. It’s a very competitive environment that requires you to constantly be on your toes, upskilling as much as possible.&lt;/p&gt;

&lt;p&gt;Naturally I’ve developed my own way of constantly learning which took me from newbie programmer to Fullstack web and mobile app developer and future DevOps engineer. I’ve learned and mastered my tech stack to a reasonable extent which  includes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ReactJs &amp;amp; NextJs for web frontend&lt;/li&gt;
&lt;li&gt;React Native for Android and IOS.&lt;/li&gt;
&lt;li&gt;NodeJS (ExpressJS and AdonisJS) for the backend&lt;/li&gt;
&lt;li&gt;MySQL and MongoDB for database&lt;/li&gt;
&lt;li&gt;AWS cloud services for deployment/hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How did I do it?&lt;/p&gt;

&lt;p&gt;I dedicated at least 1 hour a day to learning.&lt;/p&gt;

&lt;p&gt;Even back in my school days, when I had to attend lectures, do assignments and study for exams and I felt too tired to work on my tech skills, I just had to remind myself “It’s just one hour”. I’ve also found that it’s best to have that 1 hour session first thing in the morning because that is when you are least tired, it’s easier for your brain to soak in new information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Learning for Just 1 hour a day.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;1 hour of maximum focus with zero distractions is much better than 8 - 12 hours of learning that’s mixed with distractions from social media and other factors in your immediate environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can happily go about the rest of your day knowing that you’ve already dedicated a whole hour to improving your skills. Since it’s such a short period of time that ends quickly, you can anticipate the next 1 hour session the following day.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1 hour is enough time to learn enough without overloading your brain with too much information. Any information you try to assimilate beyond the 1 hour mark will probably have a hard time sticking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are leveraging the 80/20 principle which suggests that 80% of results come from just 20% of your efforts. Someone who spends 6 - 8 hours a day learning will be most focused in only the first hour or two, the remaining time will be spent learning with distractions like social media, getting hungry or thirsty, getting tired and falling asleep, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can further boost your productivity within your 1 hour session by dividing it into two 25 - 30 min sessions with a 5 min break in between where you leave your desk and go outside, at the end of both sessions, you barely feel like you’ve done any work at all.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m a big believer in the 1 hour rule as a way for tech professionals to stay constantly improving, avoiding stagnating in the fast paced tech world.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Software Development Process</title>
      <dc:creator>Ikem O</dc:creator>
      <pubDate>Tue, 01 Apr 2025 22:47:26 +0000</pubDate>
      <link>https://forem.com/ikemcodedit/my-software-development-process-2i64</link>
      <guid>https://forem.com/ikemcodedit/my-software-development-process-2i64</guid>
      <description>&lt;p&gt;Having built a couple of projects from start to finish. I’ve noticed a simple process that I naturally default to when it comes time to tackle a new Fullstack application project. Here it is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Talk to the client&lt;/strong&gt;: I first start by hopping on a call with the client so that I can listen to him explain what exactly he is trying to build. This helps me to understand what problem he is trying to solve using the software. Usually they have big ideas for their application, a whole lot of features that would take a long time to build so I try to narrow it down to the most important thing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requirements Document&lt;/strong&gt;: After the call, I ask the client to prepare a document listing and explaining each individual feature that they want in the application. Most of the time, any serious client will already have this available which he sends and I take my time to read through.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Development schedule/timeline Document&lt;/strong&gt;: One of the most important things that a client wants to know is how long the project will take to be completed. It’s difficult to just give an estimate off the top of my head, hence why the Development Schedule document is needed. All I need to do is look at each individual feature in the requirements document and assign a timeframe of 1 or 2 weeks depending on the complexity. I also throw in an extra week here and there for features that I have no experience building or have some uncertainty with. At the end, I add up all the weeks to give the total estimated time for the entire project. I also avoid trying to impress the client with short timeframes that’ll be difficult to meet up with, it’s better to give too much time and complete a feature before the deadline than to give short timeframes and miss deadlines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Figma Designs&lt;/strong&gt;: A client may already have designs available and we can get straight to work. If they don’t then I proceed to refer to them a designer to work with if they don’t know any.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Design&lt;/strong&gt;: Now that I have both a requirements document and figma designs, the next step is to study both of them and use dbdiagrams.io to do some basic database modelling just to get an overview of what tables l need to create in the database and what their relationships are. An e-commerce site for example, will have tables for users, products, orders, transactions, carts, etc. I try to predict what queries I would need to make when I start writing my controllers and I include fields in the tables that would make the queries possible. I’ve found that it’s important to not overthink this part or try to be perfect, requirements may change mid development and you can always figure things out as you go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Migration files and Models&lt;/strong&gt;: For my backend, my go to NodeJs framework is &lt;a href="https://adonisjs.com/" rel="noopener noreferrer"&gt;AdonisJS&lt;/a&gt;. I love it because it comes with libraries for building production ready applications out of the box such as auth, emails, CORS, migrations, seeders, etc. It also uses Typescript. So, I create a basic AdonisJS app, and using my Database design, I prepare database migration files and models that match, This is easy because AdonisJS framework makes use of &lt;a href="https://lucid.adonisjs.com/docs/introduction" rel="noopener noreferrer"&gt;Lucid ORM&lt;/a&gt; for handling MySQL queries under the hood.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build UI&lt;/strong&gt;: For building the UI/frontend of the application, I use ReactJS, NextJS if SEO is important. I use Atomic Design pattern, the folder structure involves categorizing my components into Templates, Organisms, Molecules and Atoms. Basically, an atom is the most simple component usually made of just one element, example is a button. A molecule is a combination of two or more elements, example is a Search bar which is a combination of an input and button. An organism is a more complex component such as a navigation bar. Finally, organisms and molecules come together to form the template for an entire page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment and Demo&lt;/strong&gt;: After completing the first feature on the development schedule, it’s time for a demo. If the client doesn’t have an AWS account then I deploy the backend on render.com  and the frontend on netlify.com or vercel.com for free. Depending on the client’s preference, we can hop on a call where I share my screen and Demo or just do a quick loom screen recording and send the link along with the Netlify or Vercel link for the client to test. I repeat this for every other feature in the document till the project is finished.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is my current process for ensuring a successful delivery of fullstack application projects. If you have any tips to give or anything I can start implementing to improve the process then I would like to hear it, thanks for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>HANDLING AUTH IN REACT APPS USING NANOSTORES AND CONTEXT API</title>
      <dc:creator>Ikem O</dc:creator>
      <pubDate>Sat, 17 Aug 2024 21:41:32 +0000</pubDate>
      <link>https://forem.com/ikemcodedit/handling-auth-in-react-apps-using-nanostores-and-context-api-35kg</link>
      <guid>https://forem.com/ikemcodedit/handling-auth-in-react-apps-using-nanostores-and-context-api-35kg</guid>
      <description>&lt;p&gt;In my beginner days of building full stack web apps with ReactJs, I found myself confused about how to handle authentication in the frontend. I mean, what should you do next after receiving your access token from the backend? How do you preserve login state?&lt;/p&gt;

&lt;p&gt;Most beginners would assume “Oh, just store your token in state”. But I found out quickly that it wasn’t the best solution, nor is it even a solution at all because, as most experienced ReactJs developers know, state is temporary because it gets cleared out each time you refresh the page and we definitely can’t have user’s logging in every time they refresh.&lt;/p&gt;

&lt;p&gt;Fast Forward to now that I've gained a little bit of experience in building full stack apps in react, studying a more experienced developer’s approach to authentication and replicating the process in two other applications, I’d like to give a guide on how I currently handle it. Some people may not think that it’s the best way but I've adopted it as my way for now and I'm open to learning other methods used by other developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  STEP ONE
&lt;/h2&gt;

&lt;p&gt;You’ve submitted your email and password (assuming you’re using basic email and password authentication) to the backend to kick off the authentication process. I will not be talking about how auth is handled in the backend because this article is about how to handle auth solely in the frontend. I will skip to the part where you have received a token in the HTTP response. Below is a code example of a simple login form component that submits the email and password to the server and receives the token and user info in the response. Now for the sake of simplicity, my form values are managed with state, it would be much better to use a robust library like &lt;a href="https://formik.org/" rel="noopener noreferrer"&gt;formik&lt;/a&gt; for production apps.&lt;br&gt;
&lt;/p&gt;

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

export default function LoginForm() {
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")

    const handleSubmit = async() =&amp;gt; {
        try {
            const response = await axios.post("/api/auth/login", { email, password })
            if (response?.status !== 200) {
                throw new Error("Failed login")
            }
            const token = response?.data?.token
            const userInfo = response?.data?.userInfo
        } catch (error) {
            throw error
        }
    }

    return(
        &amp;lt;form onSubmit={handleSubmit}&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;input name="email" onChange={(e) =&amp;gt; setEmail(e.target.value)}/&amp;gt;
                &amp;lt;input name="password" onChange={(e) =&amp;gt; setPassword(e.target.value)}/&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;button type="submit"&amp;gt;
                    Login
                &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/form&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  STEP TWO
&lt;/h2&gt;

&lt;p&gt;Wrap your entire application, or just the parts that need access to the auth state in an Auth context provider. This is commonly done in your root &lt;code&gt;App.jsx&lt;/code&gt; file. If you have no idea what context API is, feel free to check the &lt;a href="https://react.dev/reference/react" rel="noopener noreferrer"&gt;Reactjs docs&lt;/a&gt;. The examples below show an AuthContext provider component created. It is then imported in &lt;code&gt;App.jsx&lt;/code&gt; and used to wrap the RouterProvider returned in the App component, thereby making the auth state accessible from anywhere in the application.&lt;br&gt;
&lt;/p&gt;

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

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {

    return(
        &amp;lt;AuthContext.Provider&amp;gt;
            {children}
        &amp;lt;/AuthContext.Provider&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import AuthProvider from "./AuthContext";

const router = createBrowserRouter([
    // your routes here
])

function App() {
    return(
        &amp;lt;AuthProvider&amp;gt;
            &amp;lt;RouterProvider router={router} /&amp;gt;
        &amp;lt;/AuthProvider&amp;gt;
    )
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  STEP THREE
&lt;/h2&gt;

&lt;p&gt;In the auth context, you have to initialize two state variables, “isLoggedIn” and “authenticatedUser”. The first state is a boolean type which will be initially set to ‘false’ then updated to ‘true’ once login is confirmed. The second state variable is used to store the logged in user’s info such as names, email, etc. These state variables have to be included in the value for the provider returned in the context component so they can be accessible throughout the application for conditional rendering.&lt;br&gt;
&lt;/p&gt;

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

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {
    const [isLoggedIn, setIsLoggedIn] = useState(false)
    const [authenticatedUser, setAuthenticatedUser] = useState(null)

    const values = {
        isLoggedIn,
        authenticatedUser,
        setAuthenticatedUser
    }

    return(
        &amp;lt;AuthContext.Provider value={values}&amp;gt;
            {children}
        &amp;lt;/AuthContext.Provider&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  STEP FOUR
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/nanostores" rel="noopener noreferrer"&gt;Nanostores&lt;/a&gt; is a package for managing state in Javascript apps. The package provides a simple API for managing state values across multiple components by simply initializing it in a separate file and importing it in any component where you want to make use of the state or update it. But, for the purpose of storing your auth token received in the HTTP response in step one, you will be making use of &lt;a href="https://github.com/nanostores/persistent" rel="noopener noreferrer"&gt;nanostores/persistent&lt;/a&gt;. This package persists your state by storing it in localStorage, that way it doesn’t get cleared out when you refresh the page. @nanostores/react is a react specific integrations for nanostores, it makes available the &lt;code&gt;useStore&lt;/code&gt; hook for extracting values from a nanostore state.&lt;/p&gt;

&lt;p&gt;So now you can go ahead and: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install the following packages: nanostores, @nanostores/persistent and @nanostores/react. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In a separate file named &lt;code&gt;user.atom.js&lt;/code&gt; or whatever you choose to name it, initialize an ‘authToken’ store and a ‘user’ store using nanostores/persistent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import them into your login form component file and update the state with the token and user data received in your login response.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i nanostores @nanostores/persistent @nanostores/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { persistentMap } from '@nanostores/persistent'

export const authToken = persistentMap('token', null)

export const user = persistentMap('user', null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { authToken, user } from './user.atom'

 const handleSubmit = async() =&amp;gt; {
        try {
            const response = await axios.post("/api/auth/login", { email, password })
            if (response?.status !== 200) {
                throw new Error("Failed login")
            }
            const token = response?.data?.token
            const userInfo = response?.data?.userInfo

            authToken.set(token)
            user.set(userInfo)
        } catch (error) {
            throw error
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  STEP FIVE
&lt;/h2&gt;

&lt;p&gt;Now, in your auth context that wraps your app, you have to make sure that the token and user states are kept updated and made available throughout your entire app. To achieve this, you have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Import the ‘authToken’ and ‘user’ stores.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialie a useEffect hook, inside of the hook, create a ‘checkLogin()’ function which will check whether the token is present in the ‘authToken’ store, if it is, run a function to check whether it’s expired. Based on your results from checking, you either redirect the user to the login page to get authenticated OR… set the ‘isLoggedIn’ state to true. Now to make sure the login state is tracked more frequently, this hook can be set to run every time the current path changes, this way, a user can get kicked out or redirected to the login page if their token expires while interacting with the app. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize another useEffect hook which will contain a function for fetching the user information from the backend using the token in the authToken store every time the app is loaded or refreshed. If you receive a successful response, set the ‘isLoggedIn’ state to true and update the ‘authenticatedUser’ state and the ‘user’ store with the user info received in the response.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the updated &lt;code&gt;AuthProvider&lt;/code&gt; component file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext, useState } from "react";
import { authToken, user } from './user.atom';
import { useStore } from "@nanostores/react";
import { useNavigate, useLocation } from "react-router-dom";
import axios from "axios";

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {
    const [isLoggedIn, setIsLoggedIn] = useState(false)
    const [authenticatedUser, setAuthenticatedUser] = useState(null)
    const token = useStore(authToken)
    const navigate = useNavigate()
    const { pathname } = useLocation()

    function isTokenExpired() {
        // verify token expiration and return true or false
    }

    // Hook to check if user is logged in 
    useEffect(() =&amp;gt; {
        async function checkLogin () {
            if (token) {

              const expiredToken = isTokenExpired(token);

              if (expiredToken) {
                // clear out expired token and user from store and navigate to login page
                authToken.set(null)
                user.set(null)
                setIsLoggedIn(false);
                navigate("/login");
                return;
              }
            }
        };

        checkLogin()
    }, [pathname])

    // Hook to fetch current user info and update state
    useEffect(() =&amp;gt; {
        async function fetchUser() {
            const response = await axios.get("/api/auth/user", {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            })

            if(response?.status !== 200) {
                throw new Error("Failed to fetch user data")
            }

            setAuthenticatedUser(response?.data)
            setIsLoggedIn(true)
        }

        fetchUser()
    }, [])

    const values = {
        isLoggedIn,
        authenticatedUser,
        setAuthenticatedUser
    }

    return(
        &amp;lt;AuthContext.Provider value={values}&amp;gt;
            {children}
        &amp;lt;/AuthContext.Provider&amp;gt;
    )
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  CONCLUSION
&lt;/h2&gt;

&lt;p&gt;Now these two useEffect hooks created in step five are responsible for keeping your entire app’s auth state managed. Every time you do a refresh, they run to check your token in local storage, retrieve the most current user data straight from the backend and update your ‘isLoggedIn’ and ‘authenticatedUser’ state. You can use the states within any component by importing the ‘AuthContext’ and the ‘useContext’ hook from react and calling them within your component to access the values and use them for some conditional rendering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useContext } from "react";
import { AuthContext } from "./AuthContext";

export default function MyLoggedInComponent() {

    const { isLoggedIn, authenticatedUser } = useContext(AuthContext)

    return(
        &amp;lt;&amp;gt;
        {
            isLoggedIn ? 
            &amp;lt;p&amp;gt;Welcome {authenticatedUser?.name}&amp;lt;/p&amp;gt;
            :
            &amp;lt;button&amp;gt;Login&amp;lt;/button&amp;gt;
        }
        &amp;lt;/&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember on logout, you have to clear the ‘authToken’ and ‘user’ store by setting them to null. You also need to set ‘isLoggedIn’ to false and ‘authenticatedUser’ to null.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
