<?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: Joma</title>
    <description>The latest articles on DEV Community by Joma (@l0j0m).</description>
    <link>https://dev.to/l0j0m</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%2F3265631%2F46a53ddf-05a2-445c-b439-e3a781dc48c0.png</url>
      <title>DEV Community: Joma</title>
      <link>https://dev.to/l0j0m</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/l0j0m"/>
    <language>en</language>
    <item>
      <title>.NET Core: Custom middleware for authentication using JWT and Cookie</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Fri, 20 Feb 2026 12:33:57 +0000</pubDate>
      <link>https://dev.to/l0j0m/net-core-custom-middleware-for-authentication-using-jwt-and-cookie-5ebe</link>
      <guid>https://dev.to/l0j0m/net-core-custom-middleware-for-authentication-using-jwt-and-cookie-5ebe</guid>
      <description>&lt;p&gt;I will only focus on how to create a custom middleware and implement authentication logic using JSON web token stored as a cookie.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;IMiddleware interface&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;InvokeAsync function which is inherited from the interface&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom login function which calls a GenerateJSONWebToken method if login credentials are correct&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's my full code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Test.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Test.Server.Middleware
{
    public class TestMiddleware : IMiddleware
    {
        private readonly TestDatabaseContext _dbContext;

        public TestMiddleware(TestContext dbContext)
        {
            _dbContext = dbContext;
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            if (context.Request.Path.Equals("/auth/login", StringComparison.OrdinalIgnoreCase)
                &amp;amp;&amp;amp; context.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase))
            {
                await HandleLogin(context);
                return; 
            }

            await next.Invoke(context);
        }

        private async Task HandleLogin(HttpContext context)
        {

            if (!context.Request.HasFormContentType)
            {
                context.Response.StatusCode = 400;
                await context.Response.WriteAsJsonAsync(new { message = "Invalid content type." });
                return;
            }

            var form = await context.Request.ReadFormAsync();
            var username = form["KorisnikUsername"].ToString();
            var password = form["KorisnikPass"].ToString();

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsJsonAsync(new
                {
                    message = "Unesite kredencijale za pristupanje admin panelu!"
                });
                return;
            }

            var user = await _dbContext.PrijavaKorisnika
                .FirstOrDefaultAsync(u =&amp;gt;
                    u.KorisnikUsername == username &amp;amp;&amp;amp;
                    u.KorisnikPass == password
                );

            if (user != null)
            {
                try
                {
                    var tokenString = GenerateJSONWebToken(username);
                    context.Response.Cookies.Append("X-Access-Token", tokenString, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure = true });
                    context.Response.StatusCode = 200;
                    await context.Response.WriteAsync( tokenString );
                }
                catch
                {
                    context.Response.StatusCode = 500;
                    await context.Response.WriteAsJsonAsync(new { message = "Nije moguce generisati sigurnosni kljuc!" });
                }

                return;
            }

            context.Response.StatusCode = 404;
            await context.Response.WriteAsJsonAsync(new
            {
                message = "Korisnik s ovim kredencijalima ne postoji u sistemu. Pokušajte još jednom!"
            });
        }

        private string GenerateJSONWebToken(string username)
        {
            //1. claims
            var claim = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, username),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            };

            //2.key
            var env = Environment.GetEnvironmentVariable("UserAccessToken");
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(env));

            //3. generate a token
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512);
            var token = new JwtSecurityToken(

                    issuer: "https://localhost:7171",
                    audience: "https://localhost:7171",
                    claims: claim,
                    expires: DateTime.Now.AddMinutes(60),
                    signingCredentials: creds
            );


            //4. handler, writetoken
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation:
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;InvokeAsync&lt;/em&gt; function is inherited from a &lt;em&gt;IMiddleware&lt;/em&gt; interface. We use it to do two security checks and call our custom login function. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;HandleLogin&lt;/em&gt; is my custom login function which sends login credentials that come from a form (e.g.front-end application will send data using formData, such as React). If user is found (credentials are correct), then JSON web token will be created for that user only and stored as a cookie.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GenerateJSONWebToken&lt;/em&gt; is a method which returns a token created by providing a username (it is a payload) and stored as a cookie. Cookie is a much better and safer option than localStorage because token cannot be accessed by performing a XSS attack. &lt;/p&gt;

&lt;p&gt;As you already know, middlewares can invoke the next one by calling &lt;em&gt;next.Invoke(context)&lt;/em&gt;. Our custom middleware will do the exact same thing if the requested path (URL) from front-end application doesn't include &lt;em&gt;/auth/login&lt;/em&gt; part and the HTTP method is not a POST method. This is some sort of an explicit security check to ensure that the correct middleware and HTTP method are sent by a front-end application. When the HTTP method and URL are correct, the next part is all about credentials and how they are sent. I have chosen a form so I need to check whether the credentials are really sent from the form. This is a second security-check level. I extract two properties: KorisnikUsername and KorisnikPass from the form and send them to my database in order to check whether those two properties have correct key-value pairs or not. If the answer is YES, I then call a method to generate a proper JSON web token for that specific user and store it as a cookie.&lt;/p&gt;

&lt;p&gt;You can test this solution in a Postman where you'll use a localhost URL with a /auth/login part, set a method to be a POST method and as a result get this kind of a response:&lt;/p&gt;

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

&lt;p&gt;As you could notice in my code, it's all about the HttpContext which has two main properties: Request and Response. Request comes from a front-end application and Response is a server/middleware response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key steps:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Check for the requested URL and method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check for the proper content type&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check for the credentials&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If credentials are correct, generate a token and store it as a cookie which is a much safer solution&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

</description>
      <category>backend</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>security</category>
    </item>
    <item>
      <title>Dynamic tab title for your React app: two ways</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Mon, 09 Feb 2026 09:28:27 +0000</pubDate>
      <link>https://dev.to/l0j0m/dynamic-tab-title-for-your-react-app-two-ways-3dfp</link>
      <guid>https://dev.to/l0j0m/dynamic-tab-title-for-your-react-app-two-ways-3dfp</guid>
      <description>&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Using a custom hook&lt;/li&gt;
&lt;li&gt;Using React's built-in browser &lt;em&gt;title&lt;/em&gt; component&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating and calling a custom hook
&lt;/h2&gt;

&lt;p&gt;If you want to create a custom hook to handle dynamic tab title, you can do 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;import {useEffect } from 'react'

function useTabTitle(title) {

  useEffect(() =&amp;gt; {
    document.title = title;
  }, [title]);


}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;useEffect hook&lt;/strong&gt; will take a &lt;em&gt;title&lt;/em&gt; prop as its param and fire whenever the title changes.&lt;/p&gt;

&lt;p&gt;Whenever you want to set a different title for other pages, you'll just call this hook with the required param:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import useTabTitle from "../pageTtitles/changetabTitle"

const Dashboard = () =&amp;gt; {
 useTabTitle(" My dashboard");

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;This is the dashboard&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Leveraging a built-in browser component
&lt;/h2&gt;

&lt;p&gt;If you prefer much faster way and want to stick with the React's documentation (&lt;a href="https://react.dev/reference/react-dom/components/title" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt;), you can just use a &lt;em&gt;title&lt;/em&gt; tag as every other html tag in your React web application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Dashboard = () =&amp;gt; {

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;title&amp;gt;My dashboard&amp;lt;/title&amp;gt;
      &amp;lt;p&amp;gt;This is the dashboard&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

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

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Azure Blob Storage in .NET Core Web API v8</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Sun, 08 Feb 2026 20:03:16 +0000</pubDate>
      <link>https://dev.to/l0j0m/azure-blob-storage-in-net-core-web-api-v8-45ga</link>
      <guid>https://dev.to/l0j0m/azure-blob-storage-in-net-core-web-api-v8-45ga</guid>
      <description>&lt;p&gt;Azure Blob Storage allows us to store images as URIs on Azure and in our database as varchar/strings instead of keeping them as a Blob type. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For images&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;ul&gt;
&lt;li&gt;Installed NuGet package: &lt;strong&gt;Azure.Storage.Blobs&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all, we need to register a SCOPED service in our Program.cs file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddScoped(x =&amp;gt;
{
    var configuration = x.GetRequiredService&amp;lt;IConfiguration&amp;gt;();
    var connectionString = configuration["AzureBlobStorage:ConnectionString"];
    if (string.IsNullOrEmpty(connectionString))
        throw new InvalidOperationException("Azure Blob Storage connection string not found.");
    return new BlobServiceClient(connectionString);
});



builder.Services.AddScoped&amp;lt;BlobService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can continue creating our service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class BlobService
{
    private readonly BlobContainerClient _containerClient;

    public BlobService(IConfiguration config)
    {

        var connectionString = config["ConnectionStrings:AzureBlobStorage"];
        var containerName = config["AzureBlobStorage:ContainerName"];

        if (string.IsNullOrEmpty(connectionString))
            throw new Exception("Azure Blob Storage connection string not found!");

        _containerClient = new BlobContainerClient(connectionString, containerName);

    }

    //uploading an image
    public async Task&amp;lt;string&amp;gt; UploadAsync(IFormFile file)
    {
        var blobClient = _containerClient.GetBlobClient(file.FileName);
        await blobClient.UploadAsync(file.OpenReadStream(), true);

        return blobClient.Uri.ToString();
    }


    //delete the image
    public async Task DeleteAsync(string blobUrl)
    {
        var blobName = Path.GetFileName(blobUrl);
        var blobClient = _containerClient.GetBlobClient(blobName);
        await blobClient.DeleteIfExistsAsync();
    }

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

&lt;/div&gt;



&lt;p&gt;NOTE: &lt;strong&gt;connectionString and containerName are stored in appsettings.json but it would be better if they were stored as ENV values in our project&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;BlobServiceClient: This class allows us to manipulate Azure Storage resources and blob containers&lt;/li&gt;
&lt;li&gt;BlobContainerClient: This class allows us to manipulate Azure Storage containers and their blobs.&lt;/li&gt;
&lt;li&gt;BlobClient: This class allows us to manipulate Azure Storage blobs. It's very crucial for us&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;p&gt;Key steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating and registering a BlobServiceClient&lt;/li&gt;
&lt;li&gt;Creating a BlobContainerClient with provided connectionString and containerName&lt;/li&gt;
&lt;li&gt;Initializing a BlobClient with our file and its name&lt;/li&gt;
&lt;li&gt;Uploading our file to the container or optionally our database using BlobClient&lt;/li&gt;
&lt;li&gt;Deleting our file from a container or optionally our database using BlobClient
_____________________________________________________________&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Consuming our BlobService in an API controller&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Uploading an image:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var imageUrl = await _blobService.UploadAsync(novosti.FormFile);
novosti.NovostiSlikaUrl= imageUrl;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;novosti.FormFile&lt;/strong&gt; is my object which has unmapped property FormFile which I use to handle Blob types and &lt;strong&gt;NovostiSlikaUrl&lt;/strong&gt; is an object property mapped with my database's field to store these images as URI after uploading them to my Azure container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deleting an image:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; if (!string.IsNullOrEmpty(novostiobavijesti.BunjoNovostiSlikaUrl))
 {
     await _blobService.DeleteAsync(novostiobavijesti.BunjoNovostiSlikaUrl);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image is deleted from a container and from my database, too.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Deploy your React personal website using Cloudflare Hosting solution and GitHub</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Sun, 08 Feb 2026 17:17:31 +0000</pubDate>
      <link>https://dev.to/l0j0m/deploy-your-react-personal-website-using-cloudflare-hosting-solution-and-github-5db5</link>
      <guid>https://dev.to/l0j0m/deploy-your-react-personal-website-using-cloudflare-hosting-solution-and-github-5db5</guid>
      <description>&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub repo&lt;/li&gt;
&lt;li&gt;Cloudflare account&lt;/li&gt;
&lt;li&gt;wrangler.jsonc file added to the project&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;On the left side of your Cloudflare dashboard find these two tabs:&lt;/p&gt;

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

&lt;p&gt;Click on a blue button with the caption: &lt;strong&gt;Create application&lt;/strong&gt; on the right side of the page. The button will navigate you to the separate dashboard where you'll be able to choose a worker:&lt;/p&gt;

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

&lt;p&gt;Select an option to connect with GitHub, follow their simple steps, wait for them to install your dependencies and build your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Possible errors
&lt;/h2&gt;

&lt;p&gt;If there are any errors, the log will tell you what's happening and it is likely you forgot to add a &lt;strong&gt;wrangler.jsonc&lt;/strong&gt; file with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "worker-name",
    "compatibility_date": "2026-02-08",
      "assets": {
        "directory": "./dist"
      }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>devops</category>
      <category>github</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Fisher-Yates algorithm explained (C#)</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Sun, 08 Feb 2026 12:51:40 +0000</pubDate>
      <link>https://dev.to/l0j0m/fisher-yates-algorithm-explained-c-1f7k</link>
      <guid>https://dev.to/l0j0m/fisher-yates-algorithm-explained-c-1f7k</guid>
      <description>&lt;p&gt;Using the random selection method, we select elements with equal probability of selection, respecting the rule that no element in the iteration is omitted. However, the algorithm doesn't always follow that rule.&lt;/p&gt;

&lt;p&gt;In this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpPost("PasswordGenerator")]
public string GeneratePassword()
{

    const string symbols = "!@#$%^&amp;amp;*()[]{}|;:,&amp;lt;&amp;gt;?";
    const string numbers = "0123456789";
    const string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    const string allChars = symbols + numbers + letters;


    Random random = new();


    try
    {
        char[] passwordArray = allChars.ToCharArray();

        for (int i = passwordArray.Length-1; i &amp;gt; 0; i--)
        {
            int j = random.Next(i+1);
            (passwordArray[i], passwordArray[j]) = (passwordArray[j], passwordArray[i]);
        }

        return new string(passwordArray);

    }
    catch
    {
        return new string("nema passworda");
    }


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

&lt;/div&gt;



&lt;p&gt;I want to generate a random password from the given characters. In the beginning there are strings which I concat then break into an array of single characters.&lt;br&gt;
Algorithm start its job from a for loop where it picks a last character on the last index (if the last index is 21, the picked character is z)&lt;br&gt;
&lt;code&gt;int i = passwordArray.Length-1; i &amp;gt; 0; i--&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;i--&lt;/strong&gt; tells us that is going backward, not forward.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;int j = random.Next(i+1);&lt;/code&gt; is a randomly picked index between given span of indexes (if the i+1 = 10, than j has to be some random index picked between 0 and 10).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(passwordArray[i], passwordArray[j]) = (passwordArray[j], passwordArray[i]);&lt;/code&gt; --&amp;gt; this is called a tuple swap method which literally just swaps the positions. The right side (passwordArray[j], passwordArray[i]) creates a tuple with those two values, then the left side deconstructs it back into the array positions in reverse order.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Authentication and Authorization (React and ASP.NET Core Web API v8) using JSON Web Token</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Sat, 07 Feb 2026 21:58:57 +0000</pubDate>
      <link>https://dev.to/l0j0m/authentication-and-authorization-react-and-aspnet-core-web-api-v8-using-json-web-token-mck</link>
      <guid>https://dev.to/l0j0m/authentication-and-authorization-react-and-aspnet-core-web-api-v8-using-json-web-token-mck</guid>
      <description>&lt;p&gt;JWT is a modern way of authorizing a user’s access to protected sources, accepted by a server. Server generates a special token after authenticating a user. React app sends a login credentials e.g. username and password which are checked by a server. If both of them are correct, logged in user gets a “VIP ticket” which can be used all across the same web or mobile app. Generated token can be configured to expire which will make React app to ask for another token so the user can with no interruptions continue to use the app. &lt;/p&gt;

&lt;p&gt;In this example a server is Web API and client is, as you could already see, a React.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We should register a JWT configuration in Program.cs file like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.AspNetCore.Authentication.JwtBearer;

//CORS POLICY
builder.Services.AddCors(options =&amp;gt;
{
    options.AddPolicy("AllowOrigin", policy =&amp;gt;
    {
        policy.WithOrigins("http://localhost:5173")
                       .AllowAnyMethod()
               .AllowAnyHeader()
               .AllowCredentials();
    });
});


var env = Environment.GetEnvironmentVariable("UserAccessToken");
if (string.IsNullOrEmpty(env))
{
    throw new InvalidOperationException("Environment variable 'UserAccessToken' is not set.");
}

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =&amp;gt;
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "https://localhost:7171",
            ValidAudience = "https://localhost:7171",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(env))
        };
    });




app.UseAuthentication();
app.UseAuthorization();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;“UserAccessToken” is a 512 hash code that I’ve put in as a ENV property of this project (VS Studio 2022 Toolbar: Project tab &amp;gt; [Your Solution name] Properties &amp;gt; search for a env keyword)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A function which will create a token and return it
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private string GenerateJwtToken(string username)
{
    var claims = new[]
    {
         new Claim(JwtRegisteredClaimNames.Sub, username),
         new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
    };

    //var superKey = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
    var env = Environment.GetEnvironmentVariable("UserAccessToken");
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(env));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512);

    var token = new JwtSecurityToken(
        issuer: "https://localhost:7171",
        audience: "https://localhost:7171",
        claims: claims,
        expires: DateTime.Now.AddMinutes(60),
        signingCredentials: creds
    );

    return new JwtSecurityTokenHandler().WriteToken(token);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will call this function in our login function if the user credentials are correct. &lt;/p&gt;

&lt;p&gt;After receiving a 200 response from our server with a generated token, our React app will send that token whenever it wants to make another API call. But, we need to be careful! If the server set the token as a cookie (see the above example), React does not need to send a token at  all. &lt;/p&gt;

&lt;p&gt;I’ll show you the difference where token is set to localStorage by a client app and when it’s stored as a cookie by a server. Both of these are visible in our Application tab of the browser but not accessible in a same way. localStorage is vulnerable because of XSS attacks so it’s not recommended at all!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the token is set in a localStorage, React app sends API requests like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const res = await axios.get("https://localhost:7171/authentication/ControllerName/anotherapireq", {
  headers: {
    Authorization: `Bearer ${tokenSifra}`
  }
});

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;When the token is set by a server:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;axios.defaults.withCredentials = true;&lt;/code&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>react</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>useContext: simplicity matters</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Fri, 06 Feb 2026 19:41:24 +0000</pubDate>
      <link>https://dev.to/l0j0m/usecontext-simplicity-matters-3na5</link>
      <guid>https://dev.to/l0j0m/usecontext-simplicity-matters-3na5</guid>
      <description>&lt;p&gt;Props drilling is a good way of learning that nested components can send and receive properties, but in terms of simplicity and readability, props drilling is really just a pain int the a.. 😊. That's why we need useContext hook!&lt;/p&gt;

&lt;p&gt;Steps are simple:&lt;br&gt;
&lt;strong&gt;1. Create a context&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;2. Create a provider which will send properties to child components&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;3. Consume these properties&lt;/strong&gt;&lt;/p&gt;

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



&lt;p&gt;I created a parent component called Login.jsx where I handle user inputs using &lt;a href="https://dev.to/joma_3b2f21917842d7461716/usereducer-vs-usestate-2n88"&gt;useReducer hook&lt;/a&gt;. The state I want to pass to other child component Middleware.jsx is &lt;code&gt;const[isAuthenticated, setIsAuthenticated] = useState(false)&lt;/code&gt; so I've should also create a Provider which wraps child component &lt;strong&gt;providing it with isAuthenticated prop&lt;/strong&gt;. Middleware will &lt;strong&gt;consume&lt;/strong&gt; that prop and read its value whenever it changes inside parent component and render another child component, Dashboard.jsx. If the &lt;em&gt;isAuthenticated&lt;/em&gt; true, user will see rendered Dashboard but if it's not, there will be a custom message as a warning.&lt;br&gt;
If I passed a &lt;em&gt;isAuthenticated&lt;/em&gt; to the child component, what should I do with its setter function? Setter function allows me to change a state of the observable prop so the child components know what to do based on the given value.&lt;/p&gt;



&lt;p&gt;A bigger picture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a context and its hook (hook is optional but it gives us a secure fallback if we for example forget to create a provider but still passing props)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;AuthenticationContext.jsx&lt;/strong&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 { createContext, useContext } from "react";

//create a context
export const AuthenticationContext = createContext(null);


//create a custom hook to handle issues with context being null
export const useAuthenticationHook = () =&amp;gt;{
    const context = useContext(AuthenticationContext);
    if(!context){ throw new Error("Context is null, you should check your provider.")}
    return context;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Creating a provider in a parent component passing a mutable prop to a child component and handling user authentication
&lt;strong&gt;Login.jsx&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useReducer } from 'react'
import { AuthenticationContext } from './AuthenticationContext';
import Middleware from './Middleware';

const Login = () =&amp;gt; {
    //MUTABLE state
    const[isAuthenticated, setIsAuthenticated] = useState(false);
    //useReducer: initialState, dipatch, reducer | state

    const initialState = {username:'', password:''};
    function reducer (state, action){
        switch(action.type){
            case 'handleTextState':
                return {
                    ...state,
                    [action.field] : action.value

                }
        }

    }

    const[state, dispatch] = useReducer(reducer, initialState);

    function handleUserLogin(e){
        //prevent form reset
        e.preventDefault();
        //set shareable state to true if the user is correct
        /* const res = await fetch('your api endpoint for login',{
        method:'POST',
        body: JSON.stringify({state.username, state.password})
        })
        if(res.status === 200){
        setIsAuthenticated(true);
        } */

        setIsAuthenticated(true);
    }



  return (
    &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;To see your dashboard, please login first!&amp;lt;/h3&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;form onSubmit={handleUserLogin}&amp;gt;
                &amp;lt;input placeholder='Your username...' name="username" value={state.username} type="text" onChange={(e)=&amp;gt; dispatch({
                    type:"handleTextState",
                    field:e.target.name,
                    value:e.target.value
                })} /&amp;gt;

                 &amp;lt;input placeholder='Your password...' name="password" value={state.password} type="text" onChange={(e)=&amp;gt; dispatch({
                    type:"handleTextState",
                    field:e.target.name,
                    value:e.target.value
                })} /&amp;gt;
                &amp;lt;button type="submit"&amp;gt;Login&amp;lt;/button&amp;gt;
            &amp;lt;/form&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;AuthenticationContext.Provider value {{isAuthenticated}}&amp;gt;
                &amp;lt;Middleware /&amp;gt;
                &amp;lt;/AuthenticationContext.Provider&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Using a passed prop inside a child component and reading its value&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Middleware.jsx&lt;/strong&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 { useAuthenticationHook } from './AuthenticationContext'
import Dashboard from './Dashboard';

const Middleware = () =&amp;gt; {
    const {isAuthenticated} = useAuthenticationHook();
  return (
    &amp;lt;div&amp;gt;
        {
         isAuthenticated ? &amp;lt;Dashboard /&amp;gt; : &amp;lt;p&amp;gt;You need to login first!&amp;lt;/p&amp;gt;
        }
    &amp;lt;/div&amp;gt;
  )
}

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

&lt;/div&gt;



</description>
      <category>react</category>
    </item>
    <item>
      <title>useReducer vs useState</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Thu, 05 Feb 2026 19:23:02 +0000</pubDate>
      <link>https://dev.to/l0j0m/usereducer-vs-usestate-2n88</link>
      <guid>https://dev.to/l0j0m/usereducer-vs-usestate-2n88</guid>
      <description>&lt;p&gt;Both of these hooks do the same thing... but in a different way. What we write for useReducer hook, the same magic is happening 'behind the scenes' for useState (we see only it's result!). &lt;/p&gt;

&lt;p&gt;Let's see the example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. useState&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    const[contactName, setContactName] = useState("");
    const[contactImage, setContactImage] = useState(null);
    const[contactImageUrl, setContactImageUrl] = useState(null);

    function handleImageUpload(e) {
        const file = e.target.files[0];
        const fileName = e.targe.files[0].name;

        if(!file) return;

        const matchRgx = fileName.match(/\.(jpg|png|jpeg)/);
        if (matchRgx != null) {
            setContactImageUrl(URL.createObjectURL(e.target.files[0]));
        }
        else {
             setContactImage(null);
             setContactImageUrl(null);
        }
    }

    function handleForm(e) {
        e.preventDefault();
        window.alert("Successfully added a contact!");
    }

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;form onSubmit={handleForm}&amp;gt;

                &amp;lt;small&amp;gt;Name:&amp;lt;/small&amp;gt;
                &amp;lt;input
                    value={contactName}
                    type='text'
                    onChange={(e)=&amp;gt; setContactName(e.target.value)}
                /&amp;gt;

                &amp;lt;small&amp;gt;Image:&amp;lt;/small&amp;gt;
                &amp;lt;input
                    type='file'
                    accept='image/jpeg,image/png,image/jpg'
                    onChange={handleImageUpload}
                /&amp;gt;

                &amp;lt;img src={contactImageUrl} /&amp;gt;

                &amp;lt;button type='submit'&amp;gt;Submit&amp;lt;/button&amp;gt;
            &amp;lt;/form&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. useReducer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const initialFormState = { contactName: '', contactImage:null, contactImageUrl:null };

function reducer(state, action) {
    if (action.type === 'setState') {
        return {
            ...state,
            [action.field]: action.value
        };
    } else if (action.type == "ImageUpload") {
        return {
            ...state,
            contactImage: action.file,
            contactImageUrl: action.url
        }
    }
    return state;
}

const ReducerHook = () =&amp;gt; {
    const [state, dispatch] = useReducer(reducer, initialFormState);

    function handleImageUpload(e) {
        const file = e.target.files[0];
        const fileName = e.targe.files[0].name;

        if(!file) return;

        const matchRgx = fileName.match(/\.(jpg|png|jpeg)/);
        if (matchRgx != null) {
            const imageUrl = URL.createObjectURL(e.target.files[0]);
            dispatch({
                type:"ImageUpload",
                file:e.target.files[0],
                url: imageUrl
            })

        }
        else {
             dispatch({
                type:"ImageUpload",
                file:null,
                url: null
            })

        }
    }

    function handleName(e) {
        e.preventDefault();
    }

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;form onSubmit={handleName}&amp;gt;
                &amp;lt;small&amp;gt;Name:&amp;lt;/small&amp;gt;
                &amp;lt;input
                    name="contactName"
                    value={state.contactName}
                    type='text'
                    onChange={(e) =&amp;gt; {
                        dispatch({
                            type: 'setState',
                            field: e.target.name,
                            value: e.target.value
                        })
                    }}
                /&amp;gt;

                &amp;lt;small&amp;gt;Image:&amp;lt;/small&amp;gt;
                &amp;lt;img src={state.contactImageUrl} /&amp;gt;
                &amp;lt;input
                    type='file'
                    accept='image/jpeg,image/png,image/jpg'
                    onChange={handleImageUpload}
                /&amp;gt;

                &amp;lt;button type='submit'&amp;gt;Submit&amp;lt;/button&amp;gt;
            &amp;lt;/form&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;u&gt;EXPLANATION:&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
When using a useState hook, we directly define a setter functions (&lt;em&gt;something, setSomething&lt;/em&gt;) and call them for every state we want to track, differently.&lt;br&gt;
However, useReducer has its own setter function which is literally shared among states. That means that we don't need to define more setter functions for every state we want to track. That setter function is called a reducer.&lt;br&gt;
&lt;code&gt;const[state, dispatch] = useReducer(reducer, initialState)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;state&lt;/em&gt; is a container will all the data we want to manipulate with&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;dispatch&lt;/em&gt; is communicating with a reducer function by sending instructions about what should be changed and how&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;reducer&lt;/em&gt; is the actual function that submits changes&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;initialState&lt;/em&gt; is an object with all the initial states&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React v19: useTransition hook with &lt;Activity /&gt;</title>
      <dc:creator>Joma</dc:creator>
      <pubDate>Mon, 05 Jan 2026 22:37:08 +0000</pubDate>
      <link>https://dev.to/l0j0m/react-v19-usetransition-hook-with-2c4f</link>
      <guid>https://dev.to/l0j0m/react-v19-usetransition-hook-with-2c4f</guid>
      <description>&lt;p&gt;I was playing around with useTransition hook (&lt;a href="https://react.dev/reference/react/useTransition" rel="noopener noreferrer"&gt;https://react.dev/reference/react/useTransition&lt;/a&gt;) and noticed that it doesn't keep data when a particular UI component loses its focus (e.g. user navigates to somewhere else while component is rendering its content, calculating something or fetching a really heavy data), which is obvious 😉 but what if I want them to keep its data "live" and not to fetch or calculate over and over when user comes back? One of the solutions is using  wrapper 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;Activity&amp;gt;
   &amp;lt;div&amp;gt;{data}&amp;lt;/div&amp;gt;
  &amp;lt;/Activity&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activity has two props and one of them is &lt;strong&gt;mode&lt;/strong&gt; which can be &lt;em&gt;visible&lt;/em&gt; or &lt;em&gt;hidden&lt;/em&gt; (&lt;a href="https://react.dev/reference/react/Activity" rel="noopener noreferrer"&gt;https://react.dev/reference/react/Activity&lt;/a&gt;).&lt;br&gt;
If omitted, it stays &lt;em&gt;visible&lt;/em&gt; by default which is exactly what I wanted!&lt;/p&gt;

&lt;p&gt;🗝️Key steps I took:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;used useTransition hook and called startTransition function (React calls it Action)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const [isPending, startTransition] = useTransition();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;created a custom &lt;em&gt;delay&lt;/em&gt; function to simulate fetching a heavy data with dummyjson.com API and called it inside startTransition before fetching&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const delay = async (ms) =&amp;gt; {
    return new Promise((resolve) =&amp;gt; setTimeout(resolve,ms));
};


 startTransition(async () =&amp;gt; {
   if (key === "profile") {
     await delay(1100);
     await fetchData();
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;*&lt;em&gt;wrapped fetched data with Activity wrapper to keep data visible after particular UI component loses its focus *&lt;/em&gt;
&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;div&amp;gt;
      &amp;lt;Tabs
        activeKey={defaultTabKey}
        onSelect={handleTabChange}
        defaultActiveKey="home"
        id="uncontrolled-tab-example"
        className="mb-3"
      &amp;gt;
        &amp;lt;Tab eventKey="home" title="Home"&amp;gt;
          Tab content for Home
        &amp;lt;/Tab&amp;gt;
        &amp;lt;Tab eventKey="profile" title="Profile"&amp;gt;
          &amp;lt;Activity&amp;gt;
            &amp;lt;div&amp;gt;{data}&amp;lt;/div&amp;gt;
          &amp;lt;/Activity&amp;gt;
        &amp;lt;/Tab&amp;gt;
        &amp;lt;Tab eventKey="contact" title="Contact"&amp;gt;
          Tab content for Contact
        &amp;lt;/Tab&amp;gt;
      &amp;lt;/Tabs&amp;gt;
       &amp;lt;p&amp;gt;{isPending ? "Fetching data..." : ""}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎯So the result is fetched data that is always present even tough user navigates to somewhere else (in  my case when user clicks on another tab inside tab group)&lt;/p&gt;




&lt;p&gt;Full code is available at (&lt;a href="https://github.com/majalojo/reactv19.git" rel="noopener noreferrer"&gt;https://github.com/majalojo/reactv19.git&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Here's the image of the source code:&lt;/p&gt;

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




&lt;p&gt;❗&lt;strong&gt;Main gap and recommendations&lt;/strong&gt;&lt;br&gt;
We see data is present when user comes back to a profile Tab, but we also see that isPending fired again so that means startTransition and handleChange, too. Is there any solution to make useTransition and Activity cooperate, or is it a default React's DOM behaviour? So this solution should be updated in the future regarding this gap.&lt;/p&gt;

</description>
      <category>react</category>
      <category>usetransition</category>
    </item>
  </channel>
</rss>
