ReactJS Articles / Blogs / Perficient https://blogs.perficient.com/tag/reactjs/ Expert Digital Insights Mon, 07 Jul 2025 14:40:17 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png ReactJS Articles / Blogs / Perficient https://blogs.perficient.com/tag/reactjs/ 32 32 30508587 State Management in React with Jotai https://blogs.perficient.com/2025/07/07/state-management-in-react-with-jotai/ https://blogs.perficient.com/2025/07/07/state-management-in-react-with-jotai/#respond Mon, 07 Jul 2025 14:40:17 +0000 https://blogs.perficient.com/?p=382479

Imagine you’re building a React app where users can log in, get notifications, and change theme preferences. With traditional tools like Redux, managing all these states can be tricky. Lots of code, a complicated setup, and a steep learning curve. Now, with Jotai, you can handle all these states with very little code and setup. You can create “atoms” for user data, notifications, and theme settings, letting each state update on its own. This makes your app faster, easier to maintain, and free of unnecessary complexity. Jotai makes state management simple and efficient.

In my previous blog posts, I wrote about some of the most widely used state management libraries in the React ecosystem – do check them out if you haven’t already!

What is Jotai?

Jotai is a minimalist state management library for React. The name “Jotai” comes from the Japanese word jōtai, meaning “state.” With over 40,000 stars on GitHub, Jotai’s atomic model breaks down the state into small pieces called atoms, allowing for granular control and fewer re-renders.

 

Key Advantages of Using Jotai for State Management in React

Jotai Img 1

Setting Up Jotai in Your React Application

 

To set up Jotai, run this command in your project directory:

npm install jotai

 

After this, you can begin using Jotai by importing it into your React components:

 

import { atom, useAtom } from 'jotai';

 

Look at the package.json file, jotai has been installed in our project.

Jotai Dependencies

 

Let’s take an example to see how we use MobX to manage the state in our React app.

atom.jsx

import { atom } from 'jotai';

export const countAtom = atom(1);
Counter.jsx

import React from 'react';
import { useAtom } from 'jotai';
import { countAtom } from './atoms';

function Counter() {
  const [count, setCount] = useAtom(countAtom);

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;
App.jsx

import React from 'react';
import Counter from './Counter';

function App() {
  return (
    <div>
      <h1>Hello Jotai App</h1>
      <Counter />
    </div>
  );
}

export default App;


 

Jotai Img 2

This example uses Jotai to manage shared state in a React app.
The line atom(1) creates a piece of state called countAtom with an initial value of 1. This is like a global variable that can be used in any component.

In the Counter component, useAtom(countAtom) is used to get the current count and a function to update it. When the button is clicked, the count increases by 1 using setCount(count + 1).

Only components that use countAtom will re-render when the count changes. This makes Jotai more efficient than useContext or Redux, where more components might re-render unnecessarily.

If multiple components use countAtom, they all stay in sync automatically and update only when needed. This helps improve performance and keeps the code clean.

 

Like any powerful tool, Jotai has its own unique quirks and limitations that you should be aware of.

 

Manual Handling of Loading/Error States: Jotai doesn’t have built-in ways to handle loading or error states, so you need to write custom code for async operations.

 

Re-renders with Frequent Updates: Frequent state changes or adding new providers can cause unnecessary re-renders, making it less ideal for apps with lots of dynamic data.

 

Inefficient Object Equality Checks: Jotai uses reference equality (===) for objects, which can lead to extra re-renders unless you add custom checks.

 

Limited Built-in Features: Jotai doesn’t include features like dev tools or middleware, so you’ll need to add extra tools for debugging and advanced state management.

 

Performance in Large Apps: Jotai may not be as fast as other libraries for large, complex apps with frequent state updates.

 

 

Comparing Jotai with other libraries like Redux, Recoil, and MobX

 

Jotai Img 3

 

  • Jotai vs Redux: Jotai is a lightweight alternative to Redux, focusing on atomic state management without the need for actions, reducers, or a global store. It’s simpler and quicker to set up, making it ideal for smaller apps or specific components within larger projects.

 

  • Jotai vs Recoil: Both Jotai and Recoil use atomic state, but Recoil provides more built-in features like selectors for derived state and tools for handling async data. Jotai is more minimal, offering a simpler API, making it easier to integrate but with fewer out-of-the-box utilities compared to Recoil.

 

  • Jotai vs MobX: Jotai uses explicit atomic state, giving you control over what changes trigger updates. MobX, on the other hand, uses observables that automatically track dependencies. MobX can handle more complex state management needs, while Jotai is easier to understand and better for smaller, simpler apps.

 

Some FAQs about Jotai

 

  • Does Jotai support debugging tools like Redux DevTools?
    • No, Jotai doesn’t come with built-in debugging tools like Redux DevTools. However, you can still use React Developer Tools to inspect Jotai’s atoms or create your custom debugging solutions.

 

  • How do I handle asynchronous operations in Jotai?
    • You can handle async operations by using async atoms. These atoms store promises or data fetched from APIs, and you can update them once the data is available using the useAtom

 

  • Is Jotai still relevant in 2025?
    • Yes, Jotai will remain relevant in 2025 due to its simplicity, efficient atomic state management, and alignment with React’s modern patterns. It continues to be a popular choice for small to medium-sized applications.

Conclusion:

Jotai is a simple and powerful state management library for React. Its minimal API makes managing state easy, while its atomic design gives you precise control over local and global state. This makes Jotai great for projects of all sizes. Inspired by Recoil’s “atoms,” Jotai provides a clean and flexible way to manage the state. While Jotai is a great choice for developers looking for an easy and fast solution, it’s always good to explore other libraries to find the best fit for your project. Jotai also offers useful utility packages, which are fully explained in the documentation to help you get the most out of it.

And that’s a wrap for today! More insights into front-end technologies are coming your way – all geared to level up your development game. Until then, check out my other blogs, keep exploring, stay curious, and code with passion!

 

]]>
https://blogs.perficient.com/2025/07/07/state-management-in-react-with-jotai/feed/ 0 382479
Building a WordPress Plugin with React: A Step-by-Step Guide https://blogs.perficient.com/2025/05/14/building-a-wordpress-plugin-with-react-step-by-step-guide/ https://blogs.perficient.com/2025/05/14/building-a-wordpress-plugin-with-react-step-by-step-guide/#respond Wed, 14 May 2025 16:14:25 +0000 https://blogs.perficient.com/?p=381308
In this post, we’ll explore how to create a WordPress plugin using React for its frontend interface. We’ll make a “countdown timer” plugin as our example, which demonstrates key concepts such as WordPress-React integration, shortcodes, and dynamic content rendering. For this project, it is assumed that you already have a WordPress site running locally, as well as Node.js and npm installed. All of the code and commands will be provided in this post!

What We Are Building

We will create a “countdown timer” WordPress plugin that looks like this:
 
Example of countdown plugin

Example of the countdown plugin we will build with React

 
 
This timer is a great way to build anticipation for a new post, page, or feature on your website. It lets users see exactly when something new will go live, adding a touch of suspense! To use this plugin on your WordPress site, simply follow the steps below to build the plugin and place the provided shortcode – [wp_countdown_timer]– on the page  where you want the timer to appear. You can set the exact date and time for the countdown on the plugin’s settings page. When the countdown reaches zero, the user will be redirected automatically to a URL of your choosing. Before that, if a user clicks anywhere on the page, they’ll be redirected manually:
 

 

example of clicking on the page to redirect to the target URL

Click on the page where the countdown plugin is set to trigger the redirect manually

 
This is a basic example of a React component integrated into a WordPress plugin. You can customize the appearance of the countdown by modifying the accompanying CSS file. This example illustrates the fundamentals of using React within WordPress and can easily be extended with additional features. The goal of this post is to help you get started building custom WordPress plugins with React.
 

1. Setting Up the Development Environment

First, initialize your project with npm and install necessary dependencies. Create a new folder called wp-react-countdown in your WordPress project’s /plugins directory. Using the command line, cd into your new wp-react-countdown folder and run:

  npm init -y
  npm install react react-dom @vitejs/plugin-react vite

After running those commands, your wp-react-countdown folder’s structure should look like this:

  
  wp-react-countdown/
  ├── node_modules/
  ├── package.json
  └── package-lock.json

 

2. Creating the WordPress Plugin File

Make a new file in /wp-react-countdown called wp-countdown-timer.php. This is the main plugin file and serves as the entry point for the React component. In this file, we also register the plugin’s settings page, where you can configure the countdown’s target date and time, as well as the redirect URL. The final function in this file – wp_countdown_timer_shortcode() – outputs a container div that the React app will mount to.

Paste the following content into your new wp-countdown-timer.php file:

<?php
/**
 * Plugin Name: WP Countdown Timer
 * Description: A simple countdown timer that redirects when finished
 * Version: 1.0.0
 * Author: Jon Jackson
 * Text Domain: wp-countdown-timer
 */

if (!defined('ABSPATH')) {
    exit;
}

// Define plugin constants
define('WP_COUNTDOWN_TIMER_VERSION', '1.0.0');
define('WP_COUNTDOWN_TIMER_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WP_COUNTDOWN_TIMER_PLUGIN_URL', plugin_dir_url(__FILE__));

// Register activation hook
register_activation_hook(__FILE__, 'wp_countdown_timer_activate');

function wp_countdown_timer_activate() {
    add_option('wp_countdown_timer_target_date', '2025-05-16T00:00:00');
    add_option('wp_countdown_timer_redirect_url', home_url());
}

// Add admin menu
add_action('admin_menu', 'wp_countdown_timer_admin_menu');

function wp_countdown_timer_admin_menu() {
    add_menu_page(
        'Countdown Timer Settings',
        'Countdown Timer',
        'manage_options',
        'wp-countdown-timer',
        'wp_countdown_timer_admin_page',
        'dashicons-clock',
        30
    );
}

// Register settings
add_action('admin_init', 'wp_countdown_timer_register_settings');

function wp_countdown_timer_register_settings() {
    register_setting('wp_countdown_timer_settings', 'wp_countdown_timer_target_date');
    register_setting('wp_countdown_timer_settings', 'wp_countdown_timer_redirect_url');
}

// Admin page content
function wp_countdown_timer_admin_page() {
    ?>
    <div class="wrap">
        <h1>Countdown Timer Settings</h1>
        <form method="post" action="options.php">
            <?php settings_fields('wp_countdown_timer_settings'); ?>
            <?php do_settings_sections('wp_countdown_timer_settings'); ?>

            <table class="form-table">
                <tr>
                    <th scope="row">Target Date</th>
                    <td>
                        <input type="datetime-local"
                               name="wp_countdown_timer_target_date"
                               value="<?php echo esc_attr(get_option('wp_countdown_timer_target_date')); ?>"
                               class="regular-text">
                    </td>
                </tr>
                <tr>
                    <th scope="row">Redirect URL</th>
                    <td>
                        <input type="url"
                               name="wp_countdown_timer_redirect_url"
                               value="<?php echo esc_url(get_option('wp_countdown_timer_redirect_url')); ?>"
                               class="regular-text">
                        <p class="description">Where to redirect when the countdown ends</p>
                    </td>
                </tr>
            </table>

            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

// Enqueue scripts and styles
add_action('wp_enqueue_scripts', 'wp_countdown_timer_enqueue_scripts');

function wp_countdown_timer_enqueue_scripts() {
    global $post;
    if (!is_a($post, 'WP_Post') || !has_shortcode($post->post_content, 'wp_countdown_timer')) {
        return;
    }

    wp_enqueue_script(
        'wp-countdown-timer',
        WP_COUNTDOWN_TIMER_PLUGIN_URL . 'dist/assets/main.js',
        array(),
        WP_COUNTDOWN_TIMER_VERSION,
        true
    );

    $css_file = WP_COUNTDOWN_TIMER_PLUGIN_DIR . 'dist/assets/index.css';
    if (file_exists($css_file)) {
        wp_enqueue_style(
            'wp-countdown-timer',
            WP_COUNTDOWN_TIMER_PLUGIN_URL . 'dist/assets/index.css',
            array(),
            WP_COUNTDOWN_TIMER_VERSION
        );
    }

    $redirect_url = get_option('wp_countdown_timer_redirect_url', home_url());
    if (!preg_match('/^https?:\/\//i', $redirect_url)) {
        $redirect_url = home_url($redirect_url);
    }

    wp_localize_script('wp-countdown-timer', 'wpCountdownTimer', array(
        'targetDate' => get_option('wp_countdown_timer_target_date'),
        'redirectUrl' => esc_url(rtrim($redirect_url, '/'))
    ));
}

// Add shortcode
add_shortcode('wp_countdown_timer', 'wp_countdown_timer_shortcode');

function wp_countdown_timer_shortcode() {
    return '<div id="wp-countdown-timer-root" class="wp-countdown-timer"></div>';
}

 

3. Creating the React Component

Make a new folder inside /wp-react-countdown called src, and create a JSX file inside this src folder called CountdownTimer.jsx.

This file contains the React component that handles the countdown functionality. The component reads the target date and redirect URL passed in via the global wpCountdownTimer variable (whose values are set by the site’s administrator in the plugin’s settings page), and displays the countdown in the UI.

Once the target date and time is reached, the page will automatically redirect to the URL specified by the admin in the plugin settings. Before the countdown finishes, users can click anywhere on the page (except on a button, a, or input element), and they’ll be redirected manually.

Here is CountdownTimer.jsx:

import { useState, useEffect } from 'react';
import './CountdownTimer.css';

const CountdownTimer = () => {
  const [timeLeft, setTimeLeft] = useState({
    days: 0,
    hours: 0,
    minutes: 0,
    seconds: 0
  });

  useEffect(() => {
    const targetDate = new Date(window.wpCountdownTimer.targetDate);
    const redirectUrl = window.wpCountdownTimer.redirectUrl;
    
    const updateCountdown = () => {
      const now = new Date();
      const diff = targetDate - now;

      if (diff <= 0) {
        clearInterval(timer);
        if (redirectUrl) {
          window.location.href = redirectUrl;
        }
        return;
      }

      setTimeLeft({
        days: Math.floor(diff / (1000 * 60 * 60 * 24)),
        hours: Math.floor(diff / (1000 * 60 * 60)) % 24,
        minutes: Math.floor(diff / (1000 * 60)) % 60,
        seconds: Math.floor(diff / 1000) % 60
      });
    };

    const timer = setInterval(updateCountdown, 1000);
    updateCountdown();

    return () => clearInterval(timer);
  }, []);

  useEffect(() => {
    const handleDocumentClick = (event) => {
      // Check if the clicked element or any of its parents is a link - we still want to allow user to click these!
      let element = event.target;
      while (element) {
        if (element.tagName === 'A' || element.tagName === 'BUTTON' || element.tagName === 'INPUT') {
          return;
        }
        element = element.parentElement;
      }

      // If we get here, the user clicked on a part of the page with the countdown that wasn't on a link or button - redirect!
      const redirectUrl = window.wpCountdownTimer.redirectUrl;
      if (redirectUrl) {
        window.location.href = redirectUrl;
      }
    };

    // Add click listener to the document
    document.addEventListener('click', handleDocumentClick);

    // Cleanup
    return () => {
      document.removeEventListener('click', handleDocumentClick);
    };
  }, []);

  return (
    <div className="wp-countdown-timer">
      <div className="countdown-row">
        <div className="time-segment">
          <span className="time-value">{timeLeft.days}</span>
          <span className="time-label">Days</span>
        </div>
        <div className="time-segment">
          <span className="time-value">{timeLeft.hours}</span>
          <span className="time-label">Hours</span>
        </div>
        <div className="time-segment">
          <span className="time-value">{timeLeft.minutes}</span>
          <span className="time-label">Minutes</span>
        </div>
        <div className="time-segment">
          <span className="time-value">{timeLeft.seconds}</span>
          <span className="time-label">Seconds</span>
        </div>
      </div>
    </div>
  );
};

export default CountdownTimer;

 

4. CSS for Styling

Let’s add a CSS file to style the countdown component. Inside the /src folder, create a file called CountdownTimer.css:

.countdown-container {
  margin: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #000;
  color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  cursor: pointer;
}

.countdown-content {
  text-align: center;
  padding: 2rem;
}

.countdown-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  max-width: 800px;
  margin: 0 auto;
}

.wp-countdown-timer {
  text-align: center;
  padding: 2rem;
  margin: 2rem 0;
  cursor: pointer;
}

.countdown-row {
  display: flex;
  justify-content: center;
  gap: 2rem;
  flex-wrap: wrap;
}

.time-segment {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 100px;
}

.time-value {
  font-size: 2.5rem;
  font-weight: bold;
  line-height: 1;
}

.time-label {
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-top: 0.5rem;
  opacity: 0.8;
}

.completion-text {
  font-size: 2rem;
  font-weight: bold;
}

@media (max-width: 768px) {
  .countdown-row {
    gap: 1rem;
  }

  .time-segment {
    min-width: 80px;
  }

  .time-value {
    font-size: 2rem;
  }

  .time-label {
    font-size: 0.8rem;
  }

  .completion-text {
    font-size: 1.5rem;
  }
}

 

5. Add Entry Point for React Component

Inside the /src folder, create a file called main.jsx that will serve as the entry point for the CountdownTimer component:

import React from 'react';
import ReactDOM from 'react-dom/client';
import CountdownTimer from './CountdownTimer';
import './CountdownTimer.css';

document.addEventListener('DOMContentLoaded', () => {
  const rootElement = document.getElementById('wp-countdown-timer-root');
  if (rootElement) {
    ReactDOM.createRoot(rootElement).render(
      <React.StrictMode>
        <CountdownTimer />
      </React.StrictMode>
    );
  } else if (process.env.NODE_ENV === 'development') {
    // Only show error in development
    console.error('Countdown timer root element not found');
  }
});

 

6. Setting Up Vite

In your /wp-react-countdown folder, create a file called vite.config.js:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    outDir: 'dist',
    emptyOutDir: true,
    rollupOptions: {
      input: {
        main: 'src/main.jsx'
      },
      output: {
        entryFileNames: 'assets/[name].js',
        chunkFileNames: 'assets/[name].[hash].js',
        assetFileNames: (assetInfo) => {
          const info = assetInfo.name.split('.');
          const ext = info[info.length - 1];
          if (/\.(css)$/.test(assetInfo.name)) {
            return 'assets/index.css';
          }
          return `assets/[name].[hash].${ext}`;
        }
      }
    }
  }
});

 

7. Building and Development

Add these scripts to your package.json file:

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "watch": "vite build --watch"
  }
}

Your package.json file should now look like this:

{
  "name": "wp-react-countdown",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
     "dev": "vite",
    "build": "vite build",
    "watch": "vite build --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@vitejs/plugin-react": "^4.5.2",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "vite": "^6.3.5"
  }
}

Now, cd into /wp-react-countdown and run the following commands to build the project:

  npm install
  npm run build

After running these commands, your project structure should now look like this:

  wp-countdown-timer/
  ├── dist/
  ├── node_modules/
  ├── src/
  │   ├── CountdownTimer.jsx
  │   ├── CountdownTimer.css
  │   └── main.jsx
  ├── package.json
  ├── package-lock.json
  ├── vite.config.js
  ├── wp-countdown-timer.php

If you need to make any changes to the contents of the /wp-countdown-timer folder, be sure to run npm run watch in that directory so that vite automatically rebuilds when any files change.

8. Using the Plugin

To use the plugin, navigate to your WordPress admin page > “Plugins” and Activate this plugin:

Activate the plugin in WP Admin > Plugins

Activate the plugin in WP Admin > Plugins

Then, click on the “Countdown Timer” in the sidebar menu and choose a target date and a page to redirect to once that date/time is reached. Remember to click “Save Changes”:

Countdown Timer in WordPress Settings view

Countdown Timer in WordPress Settings view

Add the [wp_countdown_timer] shortcode to any page where you would like this countdown to show. A good user experience pattern is to use this countdown component on a “splash page” that redirects visitors to the homepage or another featured page:

WordPress shortcode screenshot

WordPress shortcode

Now the countdown will be displayed on that page, and will redirect to the target page that you set in the “Redirect URL” field when the countdown expires, or when the user clicks anywhere on the page where the countdown is set:

example of clicking on the page to redirect to the target URL

example of clicking on the page to redirect to the target URL

Conclusion

Creating WordPress plugins with React allows developers to create modern, interactive user interfaces while maintaining WordPress’s flexibility and ease of use. This example demonstrates a simple countdown timer, but the same principles can be applied to create more complex plugins with rich user interfaces and interactive features.

]]>
https://blogs.perficient.com/2025/05/14/building-a-wordpress-plugin-with-react-step-by-step-guide/feed/ 0 381308
Plop.js – A Micro-Generator Framework: Template Creation https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-template-creation-part-2/ https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-template-creation-part-2/#respond Thu, 20 Mar 2025 11:28:49 +0000 https://blogs.perficient.com/?p=379015

Continuing our Plop.js journey from the last blog. Be sure to go back and read the previous installment in this series.

In our previous discussion, we explored an introduction to Plop.js and its installation in a Next.js project. Additionally, we looked at a basic skeleton of plopfile.js.

Plopfile Js Config

Understanding the Components of plopfile.js

As we saw earlier, the plopfile.js consists of key elements that define the generation. Let’s break them down again for clarity:

  • The “setGenerator” creates a plop generator. Here, plopfile.js has a single generator called “basics.”
  • The “description,” as the name suggests, describes the purpose of the generator.
  • The “prompts” is an array of prompts. This could be added to your created generator.
  • The “actions” take the user’s information to each prompt. It is an array of where each action is an object. This is an important step and requires creating some templates.

Creating Our First Template

Before creating a template, understand the concept of actions inside “setGenerator.” After all, this is where the real magic happens. Let’s write a generator to create a new component.

Plopfile Js Config Create Component

plop.setGenerator("component", {
  description: "Create a new React component",
  prompts: [
    {
      type: "input",
      name: "name",
      message: "What is this component’s name?",
    },
  ],
  actions: [
    {
      type: "add",
      path: "src/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
      templateFile: "plop-template/component.hbs",
    },
  ],
});

Breaking Down the Code

  • In the above example, we use the “add” action type, which creates a file at the specified “path” and fills it with a skeleton defined in “templateFile.”
  • Plop relies on Handlebars (Handlebars.js), a templating engine for generating structured text like HTML or JavaScript files.
  • Notice that the “templateFile” ends with a .hbs extension, which signifies a Handlebars template.

Exploring More Actions

Apart from “add”, there are several other built-in actions like:

  • “addMany”
  • “modify”
  • “append”
  • “custom” (for fully customized actions)

You can explore the complete list here: Plop.js Built-in Actions.

Organizing Templates in a Folder

Now that we understand actions, let’s organize our template files.

  1. First, create a new folder called plop-template at the root of your project.
  2. Inside this folder, create different Handlebar templates for various file types, such as:
    • .tsx for React components
    • .scss for styles
    • .md for documentation
    • .test.tsx for test cases

Handlebars Syntax Example

In Handlebars, variables are enclosed within double curly braces {{}}. Moreover, built-in helpers like “pascalCase” allow the formatting of variables.

Component Handlebar

const {{pascalCase name}} = () => {
  return <div>{{pascalCase name}} Component</div>;
};

export default {{pascalCase name}};

 

In addition to “pascalCase,” you can also use:

  • “camelCase”
  • “snakeCase”
  • “lowerCase”

Check out the complete list here: Plop.js Built-in Helpers.

Running the Generator Using Plop

After setting everything up, we are now ready to run our generator! There are two ways to do this:

1. Using CLI Command

Run Generate ScriptRun Generate Script Running

2. Using VS Code Script Runner

Alternatively, you can open the package.json file, hover over “generate script,” and click “Run Script” in your editor.Generate Plop Script Runner

Generating Our First Component with Plop

Next, let’s create our first real component, “Button,” using the plop command npm run generate (with either of the two options mentioned above). After you run the command, the terminal will show prompts as mentioned in the plopfile.js

This will prompt you with questions as per plopfile.js, such as:

  1. What is this component’s name? → Button
  2. HTML element (default is div)? → button

Run Generate Script First Component

Once you provide the inputs (refer to the above screenshot to understand better), the component gets created at the specified location, and you will see a success message in the terminal.

Final Component Created

Final Thoughts

As you can see, Plop.js simplifies component creation by automating file generation and reducing repetitive tasks. By setting up structured templates, we ensure consistency and boost productivity across the project.

In the upcoming blog, we will explore:

  • Other key Plop.js methods (beyond “setGenerator”)
  • Built-in and custom actions
  • More practical examples

So, stay tuned!

]]>
https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-template-creation-part-2/feed/ 0 379015
Plop.js – A Micro-Generator Framework: Introduction and Installation https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-introduction-and-installation-part-1/ https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-introduction-and-installation-part-1/#comments Thu, 20 Mar 2025 10:43:16 +0000 https://blogs.perficient.com/?p=378891

We may all have encountered this situation countless times in our projects—copying and pasting files just to create a new component, page, or service. Unfortunately, this slows us down and hampers our productivity by introducing errors into the workflow. However, there’s a solution! Plop.js is the answer to this problem, as it automates these tasks and allows us to focus on writing great code.

What is Plop.js?

Plop.js is a simple yet powerful scaffolding tool—in other words, a micro-generator framework—that helps us automate repetitive coding tasks for projects. It saves time, reduces errors, and standardizes code structures. Moreover, it ensures uniformity across files, making life easier for the entire team.

Highlight Features

  • First and foremost, Plop.js is a template-based file generator.
  • Additionally, it is an interactive CLI, enabling a smoother user experience.
  • Lastly, you can achieve extensibility through custom actions.

Installation of Plop.js

Plop.js can be installed in any of your projects. To illustrate this, let’s take an example of a Next.js project.

Step 1: Create a Next.js Project

To begin with, create a Next.js project using the following command:

Nextjs Installation Cli

As a result, the above CLI command will prompt you with further questions for setting up your Next.js project.
(Select answers as per your requirement):

  • What is your project named? my-app
  • Would you like to use TypeScript? No / Yes
  • Would you like to use ESLint? No / Yes
  • Would you like to use Tailwind CSS? No / Yes
  • Would you like your code inside a ‘src/’=’ directory? No / Yes
  • Would you like to use App Router? (recommended) No / Yes
  • Would you like to use Turbopack for ‘next dev’? No / Yes
  • Would you like to customize the import alias (‘@/*’ by default)? No / Yes

Step 2: Install Plop.js

Once your Next.js project is set up, navigate to the project folder and install Plop.js using the command below:

Install Plop

This Installation Generates 3 Key Files

  1. A node_modules folder for all your libraries, packages, and third-party code.
  2. A package.json file will give you a starting point for your scripts.
  3. A package-lock.json file will lock down the versions for each package.
    Plop Project Scaffolding

In addition to this, installing Plop globally is optional but recommended:

Install Plop Globally

Step 3: Create plopfile.js

Next, create a plopfile.js at the root of your project. Below is a very basic example of plopfile.js

Plopfile Js Config

module.exports = function (plop) {
  plop.setGenerator("basics", {
    description: "My first Plop generator",
    prompts: [
      {
        type: "input",
        name: "name",
        message: "What is the name of your component?",
      },
    ],
    actions: [
      {
        type: "add",
        path: "./components/{{pascalCase name}}.js",
        templateFile: "templates/component.hbs",
      },
    ],
  });
};

Breaking Down the Code

  • The “setGenerator” creates a plop generator. Here, plopfile.js has a single generator called “basics.”
  • The “description,” as the name suggests, describes the purpose of the generator.
  • The “prompts” is an array of prompts. This could be added to your created generator.
  • The “actions” take the user’s information to each prompt. It is an array of where each action is an object. This is an important step and requires creating some templates.

Step 4: Add a Script to package.json

Before running Plop, add the following script (highlighted in the screenshot below) to package.json.

Generate Plop Script

Step 5: Run plop

Lastly, run plop through the CLI command “npm run generate.”

Run Generate Script

Now, Plop will execute and guide you through the component creation process!

What’s Next?

So far, we’ve covered the introduction and installation of Plop.js and a basic skeleton for plopfile.js.
In the next partPlop.js Template Creation, we will explore plopfile.js more thoroughly, replace the skeleton code with working code, and create our first real template. Stay tuned!

]]>
https://blogs.perficient.com/2025/03/20/plop-js-a-micro-generator-framework-introduction-and-installation-part-1/feed/ 1 378891
Implementing a Fuzzy Search in React JS Using Fuse.JS https://blogs.perficient.com/2025/03/17/implementing-a-fuzzy-search-in-react-js-using-fuse-js/ https://blogs.perficient.com/2025/03/17/implementing-a-fuzzy-search-in-react-js-using-fuse-js/#comments Mon, 17 Mar 2025 10:54:13 +0000 https://blogs.perficient.com/?p=378756

When setting up client search, we usually rely on string comparison methods like indexOf, contains, etc. These methods work fine, but in real-life situations, users may search using incorrect spellings, jumbled sentences, and so on. Fuzzy Search helps us solve these issues.

Fuzzy Search

Fuzzy Search, also known as Approximate String Matching, is a technique for finding strings that are similar but not exactly the same.

Now, let’s get started with building the application.

We’ll set up a basic page that includes text and a search box.

Fuzz View

Basic React App for Search Demo

A simple React application to demonstrate the search functionality.

Regular Search

Typically, we use string comparison methods like indexOf, contains, etc. These work well, but they fail to provide results if the search query contains spelling mistakes.

Item.js

Displays individual items with their logo, name, and tags.

import React from "react";

const Item = (props) => {
  return (
    <div className="item">
      <div className="logo">
        <img src={props.logo} alt={props.name} />
      </div>
      <div className="name">
        <p>{props.name}</p>
        <div className="tags">{props.tags.join(", ")}</div>
      </div>
    </div>
  );
};

export default Item;

Data.js

Contains various objects representing different technologies with their names, logos, and tags.

[
  {
    "name": "Booty Bounce",
    "logo": "https://cdn.worldvectorlogo.com/logos/bootstrap-4.svg",
    "tags": ["dancing-css", "boot-stomping", "html-hop", "sass-swing"]
  },
  {
    "name": "React-o-Rama",
    "logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1280px-React-icon.svg.png",
    "tags": ["spinny-js", "state-masters", "fronty-mcfrontend"]
  },
  {
    "name": "Angu-latte",
    "logo": "https://angular.io/assets/images/logos/angular/angular.png",
    "tags": ["typescript-tornado", "web-zest", "framework-feels"]
  },
  {
    "name": "Vue-tiful Bliss",
    "logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/1200px-Vue.js_Logo_2.svg.png",
    "tags": ["zen-js", "pretty-view", "framework-bae"]
  },
  {
    "name": "Ant Party",
    "logo": "https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg",
    "tags": ["system-sass", "fancy-ui", "antd-vibes"]
  },
  {
    "name": "Git Giggle",
    "logo": "https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png",
    "tags": ["commit-fun", "repo-riff", "c-git-jig"]
  },
  {
    "name": "Gruntastic",
    "logo": "https://gruntjs.com/img/og.png",
    "tags": ["js-run-wild", "task-mania"]
  },
  {
    "name": "jQuirky",
    "logo": "https://w7.pngwing.com/pngs/265/442/png-transparent-jquery-octos-global-javascript-library-document-object-model-ajax-framework-text-trademark-logo-thumbnail.png",
    "tags": ["selecto-magic", "fun-dome", "libra-party"]
  },
  {
    "name": "D3-Licious",
    "logo": "https://raw.githubusercontent.com/d3/d3-logo/master/d3.png",
    "tags": ["data-candy", "viz-buzz", "chart-bliss"]
  }
]

Setting.js

The code implements a search feature in a React app where users can search tools and technologies by name or tags. It filters the data in real time, making the search case-insensitive, and updates the displayed results as the user types in the search box.

import React, { useState } from "react";
import data from "./data.json";
import Item from "./item";

const SettingsPage = () => {
  const [searchData, setSearchData] = useState(data);
  const searchItem = (query) => {
    if (!query) {
      setSearchData(data);
      return;
    }
    query = query.toLowerCase();

    const finalResult = [];
    data.forEach((item) => {
      if (
        item.name.toLowerCase().indexOf(query) !== -1 ||
        item.tags.includes(query)
      ) {
        finalResult.push(item);
      }
    });
    setSearchData(finalResult);
  };
  return (
    <div>
      <p className="title">Tools & Technologies</p>
      <div className="search-container">
        <input
          type="search"
          onChange={(e) => searchItem(e.target.value)}
          placeholder="Search Technologies"
        />
      </div>

      <div className="item-container">
        {searchData.map((item) => (
          <Item {...item} key={item.name} />
        ))}
      </div>
    </div>
  );
};

export default SettingsPage;

Output

Searched bot

Regularsearchop1

Searched booty

Regularsearchop2

I tried searching for “booty” and “bot,” but it only showed results for “booty” because the string comparison method works that way. We need a different string comparison algorithm to make the search fuzzy.

Many algorithms are available for this; you don’t need to study them all to use one.

To turn our search into a fuzzy search engine, we will use Fuse.js.

Fuse.js is a quick and lightweight fuzzy search library that doesn’t require any dependencies.

Integrating Fuse.js with Search

We can easily turn our search into a fuzzy one by making a small change.

setting.js

Implements the fuzzy search functionality using Fuse.js. It allows users to search through the technologies by their name and tags. The search results are refreshed instantly as the user types.

import React, { useState } from "react";
import data from "./data.json";
import Fuse from "fuse.js";
import Item from "./item";

const SettingsPage = () => {
  const [searchData, setSearchData] = useState(data);
  const searchItem = (query) => {
    if (!query) {
      setSearchData(data);
      return;
    }
    const fuse = new Fuse(data, {
      keys: ["name", "tags"]
    });
    const result = fuse.search(query);
    const finalResult = [];
    if (result.length) {
      result.forEach((item) => {
        finalResult.push(item.item);
      });
      setSearchData(finalResult);
    } else {
      setSearchData([]);
    }
  };
  return (
    <div>
      <p className="title">Tools & Technologies</p>
      <div className="search-container">
        <input
          type="search"
          onChange={(e) => searchItem(e.target.value)}
          placeholder="Search Technologies"
        />
      </div>

      <div className="item-container">
        {searchData.map((item) => (
          <Item {...item} key={item.name} />
        ))}
      </div>
    </div>
  );
};

export default SettingsPage;

Output

Searched bot

Fuseop1

Searched booty

Fuseop2

 

Conclusion

This blog explored how traditional string comparison methods fall short in handling misspellings and inaccuracies in search queries. Fuzzy Search, implemented using Fuse.js, provides an efficient solution by enabling approximate string matching, making the search experience more robust and user-friendly. By integrating Fuse.js into a simple React application, we created a real-time case-insensitive, flexible search functionality that can deliver accurate results even for imperfect queries. This lightweight library is a game-changer for enhancing search features in modern applications.

]]>
https://blogs.perficient.com/2025/03/17/implementing-a-fuzzy-search-in-react-js-using-fuse-js/feed/ 1 378756
Using TypeScript with React: Best Practices https://blogs.perficient.com/2025/03/05/using-typescript-with-react-best-practices/ https://blogs.perficient.com/2025/03/05/using-typescript-with-react-best-practices/#comments Thu, 06 Mar 2025 04:09:50 +0000 https://blogs.perficient.com/?p=378186

Nowadays, TypeScript has become the first choice for building scalable and maintainable React applications. By combining the approaches for static typing with dynamic capabilities of React, TypeScript enhances productivity, improves the readability of code and reduces the runtime errors. In this blog, we will explore best practices for using TypeScript in React projects, covering type safety, event handling, configuration, and utility types

1. Configuring TypeScript in a React Project
To start with TypeScript in a React project, one need to set up the configurations of TypeScript correctly. Configure tsconfig.json appropriately. The tsconfig.json file is essential for defining TypeScript rules and compiler options. Below is a basic configuration for a React project:

Picture1

2. Strict Type Checking
Enforce strict Mode
Enable strict mode in your tsconfig.json to ensure stricter type checking and improved error detection. It activates several useful checks, including:
noImplicitAny: Prevents TypeScript from inferring any type implicitly, enforcing explicit type annotations.
strictNullChecks: Ensures variables cannot be assigned null or undefined unless explicitly declared.

Picture2

This setting activates a suite of checks like noImplicitAny, strictNullChecks, and more, ensuring your code adheres to TypeScript’s rigorous standards.

Example
Without strict mode

Picture3

With strict mode:

Picture4

3. Typing Props and State
Use interface or type for Props
Define prop types explicitly for better clarity and IDE support. Instead of relying on PropTypes, use TypeScript interfaces or type aliases:

Picture5

For components with dynamic keys:

Picture6

Typing State
Use the useState hook with a type to define state. It ensures the predictable state values:

Picture7

4. Using TypeScript with Events
React events can be strongly typed with TypeScript to ensure correctness and handle incorrect event handling.
Example: Handling Form Events

Picture8

5. Default Props and Optional Props
Setting Default Props
You can provide default values for props:
Providing default values to props ensures that the component functions correctly even if a prop is not provided.

Picture9

Optional Props
Make props optional by adding a ‘?’ , which allows flexibility in component usage:

Picture10

6. Utility Types
TypeScript provides utility types to simplify common tasks.
Examples
Partial
Make all property optional:

Picture11

Pick
Pick specific properties from a type:

Picture12

Conclusion
TypeScript offers an improved type of safety and better developer experience which makes it the valuable addition to React development. We can build more reliable and maintainable React applications by applying their learning and practices.

]]>
https://blogs.perficient.com/2025/03/05/using-typescript-with-react-best-practices/feed/ 1 378186
Suspense in Action: Simplifying Async Data Fetching in React https://blogs.perficient.com/2025/01/30/suspense-in-action-simplifying-async-data-fetching-in-react/ https://blogs.perficient.com/2025/01/30/suspense-in-action-simplifying-async-data-fetching-in-react/#respond Thu, 30 Jan 2025 07:03:25 +0000 https://blogs.perficient.com/?p=376219

Building React apps often involves dealing with async data fetching. This can be complex and impact the user experience. React Suspense is here to help, making async data fetching simpler and more efficient. It improves your app’s performance and user experience.

React Suspense streamlines async data fetching. It lets you focus on building your app without data fetching worries. With Suspense, managing async data becomes easier, simplifying your code.

Discovering React Suspense’s benefits for async data fetching reveals its power. It helps create efficient, scalable apps. By using Suspense, you enhance your app’s user experience.

Introduction to React Suspense

React Suspense is a game-changer for async data fetching. It offers many benefits. Suspense makes your apps more efficient and user-friendly, and it’s simple to use and maintain.

Key Takeaways

  • You can simplify async data fetching using React Suspense
  • Suspense improves the user experience of your React applications
  • React Suspense reduces the complexity of async data fetching
  • You can create more efficient and scalable applications with Suspense
  • React Suspense is easy to implement and maintain
  • Suspense is a powerful feature for handling async data

Understanding React Suspense for Async Data

React Suspense changes how we handle async data in React apps. It lets you pause a component tree until certain conditions are met. This makes managing async data easier and improves the user experience.

React Suspense is all about making async data fetching more efficient. It lets you show a fallback UI while data loads. This is great for slow networks or big datasets.

What Makes Suspense Different from Traditional Methods

React Suspense is different because it simplifies handling async data. It avoids the complexity of old methods. These often needed many libraries and custom code.

The Evolution of Data Fetching in React

Data fetching in React has grown a lot over time. React Suspense makes it more efficient and scalable. It helps create apps that are more responsive and user-friendly.

Core Concepts Behind Suspense

1.React’s Rendering Process

React’s primary job is to render components efficiently. It achieves this by:

  • Creating a Virtual DOM: A lightweight copy of the actual DOM.
  • Diffing: Comparing the old Virtual DOM with the new one to identify changes.
  • Updating the Real DOM: Applying only the necessary updates to the browser’s DOM.

When rendering a component tree, React needs to know the output of each component. If some data is missing (e.g., API responses or dynamically imported components), React has to decide what to render in the meantime. This is where Suspense comes in.

2.The Role of Promises in React Suspense

At the core of Suspense lies React’s ability to handle JavaScript promises.

  • When React encounters a Suspense boundary (a component wrapped in <Suspense>), it expects the components inside it to either:
    • Render synchronously, or
    • Return a promise if they are waiting for data or lazy-loading.
  • If a promise is returned, React pauses the rendering process for that part of the tree until the promise resolves.

3. Steps React Takes Internally

Here’s a detailed breakdown of what happens when Suspense encounters a lazy-loaded component or asynchronous data:

      1: Initial Render

  • React begins rendering the component tree from top to bottom.
  • When it encounters a lazy-loaded component (via React.lazy) or a data-fetching hook (like useSuspenseQuery), it triggers an asynchronous operation that returns a promise.

      2: Suspending the Render

  • If a promise is returned, React marks the rendering as “suspended.”
  • React checks for a Suspense boundary in the parent tree.
    • If a Suspense boundary is found, React renders the fallback content defined in the boundary.
    • If no Suspense boundary exists, React throws an error because it cannot handle the pause without a fallback.

      3: Fallback UI

  • The fallback UI (like a loading spinner) is displayed immediately.
  • Meanwhile, React continues tracking the promise, waiting for it to resolve.

      4: Resuming the Render

  • When the promise resolves:
    • React retries rendering the suspended component.
    • It replaces the fallback UI with the resolved content.

      5: Commit Phase

  • Once the entire tree is rendered (including the resolved content), React commits the final output to the DOM.

4. How Suspense Works with Fiber Architecture

React’s Fiber architecture is what makes Suspense possible. Fiber is a reimplementation of React’s reconciliation algorithm designed for better handling of asynchronous rendering.

Key Features of Fiber in Suspense:

  1. Interruptible Rendering: Fiber allows React to pause and resume rendering as needed. This is crucial for Suspense, as rendering can be paused when waiting for a promise.
  2. Work Units: Each component in the tree is treated as a “unit of work.” When a promise is encountered, React can skip the suspended unit and continue working on other parts of the tree.
  3. Priority Levels: Fiber assigns priorities to updates. For example:
    • User interactions (like clicks) have high priority.
    • Data fetching has lower priority.

This prioritization ensures a smooth user experience even when rendering is paused.

5. Key Internals of Suspense

Promise Handling

React hooks into JavaScript promises using a mechanism called “thenable tracking.”

  • When a component throws a promise, React catches it and:
    • Tracks the promise in an internal queue.
    • Marks the component as “suspended.”
    • Waits for the promise to resolve.

Fallback Rendering

Suspense boundaries maintain a reference to their fallback UI. When React detects a suspension, it replaces the suspended part of the tree with this fallback.

Retry Mechanism

When the promise resolves, React retries rendering the suspended component. This is done efficiently by reusing previously completed parts of the tree and updating only the suspended section.

6. Advanced Concepts

Data Fetching and Suspense

React Suspense doesn’t fetch data on its own. It requires libraries like React Query, Relay, or custom hooks to throw promises during data fetching.

Concurrent Mode

In React’s Concurrent Mode (experimental), Suspense shines even brighter:

  • It enables React to work on multiple rendering tasks simultaneously.
  • Suspense boundaries can coordinate between different states (e.g., transitioning from a loading spinner to actual content smoothly).

Transitions

React can use Suspense to manage transitions. For instance:

  • A transition can show old content while waiting for new data.
  • Once the data is ready, Suspense swaps out the old content for the new one seamlessly.

7. Example of Suspense Internals in Action

Picture1

What Happens Internally:

  1. fetchUserData() returns a promise.
  2. React detects the thrown promise and pauses rendering.
  3. The Suspense boundary renders the fallback UI.
  4. After 2 seconds, the promise resolves, and React retries rendering UserProfile.
  5. The actual content replaces the fallback.

 

Conclusion: Future-Proofing Your React Applications with Suspense

React Suspense is a game-changer for async data fetching. It makes your React apps better and future-proof. It ensures a smooth user experience, handles loading states well, and fixes errors.

To keep your React apps ahead, stay updated with React’s latest. Using React Suspense lets you use new tech and give users top-notch performance. Suspense makes your apps ready for new user needs and tech.

Success comes from always learning and using the best practices. Check out lots of resources, try Suspense in your projects, and follow React’s growth. This way, your apps will always be leading the pack.

 

]]>
https://blogs.perficient.com/2025/01/30/suspense-in-action-simplifying-async-data-fetching-in-react/feed/ 0 376219
Implementing Nested Routes with React Router 6 https://blogs.perficient.com/2025/01/27/implementing-nested-routes-with-react-router-6/ https://blogs.perficient.com/2025/01/27/implementing-nested-routes-with-react-router-6/#comments Mon, 27 Jan 2025 07:10:47 +0000 https://blogs.perficient.com/?p=376180

In React Router version 6, nesting routes are a straightforward way to render multiple components within the same layout based on the URL path. This feature is especially useful for applications where you want to display different sections of content without navigating away from the current page. It’s ideal for scenarios like forums, blogs, or dashboards, where users can explore different levels of content while maintaining the same overall page structure.

Step 1: Basic Routing

React app using react-router-dom. It defines three routes: the Home component for the root URL (/), the Posts component for /posts, and the About component for /about. The <Router> component wraps around the routes to enable navigation, and the <Routes> component handles the matching of URLs to the respective components.

app.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import About from './components/about.js';
import Posts from './components/posts.js';
import Home from './components/home.js';
import './App.css';

function App() {
  return (
    <div className="App">
        <Router>
           <Routes>
                <Route path='/' element={<Home />} />
                <Route path='/posts' element={<Posts />} >
                <Route path='/about' element={<About />} />
            </Routes>
        </Router>
    </div>
  );
}

export default App;

In the app above, the routes defined are:

  • “/”
  • “/posts”
  • “/about”

Notice that in React Router 6, you don’t need to prefix paths with a forward slash (“/”) in the path props. For instance, instead of writing “/about”, you just use “about”. The leading slash is automatically implied.

 

Step 2: Nested Routing

http://localhost:3000/posts/

Setting up nested routes is straightforward! Here’s how you can do it:

app.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import About from './components/about.js';
import Posts from './components/posts.js';
import Home from './components/home.js';
import NewPostCreate from './components/newpostcreate.js';
import SinglePost from './components/singlepost'; 
import './App.css';

function App() {
  return (
    <div className="App">
        <Router>
           <Routes>
                <Route path='/' element={<Home />} />
                <Route path='posts' element={<Posts />} >
                       <Route path='newpostcreate' element={<NewPostCreate />} /> {/* Nested route for creating a post */}
                       <Route path=':postId' element={<SinglePost />} /> {/* Nested route for viewing a single post */}
                </Route>
                <Route path='about' element={<About />} />
            </Routes>
        </Router>
    </div>
  );
}

export default App;

Within a <Route> component, you can place additional <Route> components to define nested routes. Here’s how the structure would look:

  • “/”
  • “/about”
  • “/posts”
  • “/posts/newpostcreate”
  • “/posts/123”

With this setup, nested routes can share data and render it hierarchically. Now, we can explore how these nested routes pass information between each other and ensure proper display within their nested contexts.

 

Step 3: Nesting routes with <Outlet/>

http://localhost:3000/posts/newpostcreate

When you visit http://localhost:3000/posts/newpostcreate, you’ll see both the parent and child components. This happens because of nested routes—you can display multiple components under a single route.

However, if the < NewPostCreate/> component doesn’t show up, it’s because the parent <Posts /> component needs to include an <Outlet />. The <Outlet /> is a React Router feature that renders child components within a parent component.

For example, your Posts component might look like this:

posts.js

import { Outlet } from "react-router-dom";
import React from 'react'; 

export default function Posts() {
  const [currentUser] = React.useState("Faizan Ali")

    return (
        <div>
            <h1>List of posts go here!</h1>
            <Outlet context={[currentUser]}/>
        </div>
    )
}

The <Outlet /> component in React Router works similarly to props.children in regular React. It is a placeholder for displaying nested child routes within the main route.

You may be curious how to transfer data from a parent route to its child route. In React Router 6, the <Outlet /> component has a built-in context prop. This context is essentially a React context provider, allowing you to pass an array of states or values to the child components rendered inside the outlet.

newpostcreate.js

import { useOutletContext } from "react-router-dom";
import React from 'react'; 

export default function NewPostCreate() {
  const [currentUser] = useOutletContext()

    return (
        <div>
            <h1>Welcome {currentUser}, write a new post!</h1>
         <form/>
        </div>
    )
}

The <Outlet /> component in React Router works similarly to props.children in regular React. It functions as a placeholder that allows nested child routes to be displayed within the parent route.

You may wonder how to transfer data from parent to child routes. In React Router 6, the <Outlet /> component has a built-in context prop. This context is essentially a React context provider, allowing you to pass an array of states or values to the child components rendered inside the outlet.

Output:

http://localhost:3000/posts/

Posts

 

http://localhost:3000/posts/NewPostCreate

Posts Newpostcreate

 

To use <Outlet /> with context:

  • The parent must import the Outlet.
  • The parent component must include the <Outlet /> with a context, such as [state], when rendering.
  • The child must import useOutletContext.
  • The child must destructure the array using OutletContext (). In this case, order matters, unlike props and object destructuring, where the order doesn’t affect the outcome.

Now, on to the following nested route: postId.

Step 4: Nested Routes and useParams

http://localhost:3000/posts/123

singlepost.js

import { useParams } from "react-router-dom"

function SinglePost() {

    let params = useParams()

    return <h1>{params.postId}</h1>
}
export default SinglePost;
  • To display a specific post at /posts/123, we define a route with a dynamic parameter, represented by the colon: in the path:<Route path=’:postId’ element={<SinglePost />} />
  • Next, use useParams inside the component to retrieve the route parameters: let params = useParams();
  • Now, you can access the post ID (like 123 or any other value passed in the URL) by referencing params.postId within your component.

Output

http://localhost:3000/posts/123

Posts 123

 

 

In conclusion, React Router 6 simplifies nesting routes, enabling efficient hierarchical navigation. Using components like <Outlet /> and useParams, developers can easily create dynamic, interactive applications while sharing data between parent and child routes. This makes it an excellent choice for building complex, seamless user experiences.

]]>
https://blogs.perficient.com/2025/01/27/implementing-nested-routes-with-react-router-6/feed/ 1 376180
Why Choose TypeScript Over JavaScript? https://blogs.perficient.com/2025/01/20/why-choose-typescript-over-javascript/ https://blogs.perficient.com/2025/01/20/why-choose-typescript-over-javascript/#respond Mon, 20 Jan 2025 08:01:45 +0000 https://blogs.perficient.com/?p=375901

JavaScript is a loosely typed language which is very dynamic in nature. It has been very popular for its strong web development for decades. Indeed, it is a powerful tool, but it can sometimes lead to huge codebase and runtime errors, mainly in heavy applications. Now, speak about TypeScript, a superset of JavaScript, overcoming its technical challenges. Let’s know why the TypeScript is gaining the popularity and attention among high end developers.

What is TypeScript?

TypeScript, the hero programming language, is developed and maintained by Microsoft. It is built on top of JavaScript by adding various features such as interfaces, error detection capabilities, static typing. It helps developers to write the cleaner, neater and more flexible code. Since the TypeScript compiles to JavaScript, it goes very well in terms of compatibility with JavaScript libraries and frameworks

Key Advantages of TypeScript

  1. Static Typing

Think about your last debugging session: Have you ever spent time tracking down a bug caused by a type mismatch? Let’s see how TypeScript solves this with static typing.

JavaScript Example:

Picture1

What do you think happens when we use TypeScript?

TypeScript Example:

Picture2

Static typing ensures that type mismatches are caught during the development phase, reducing bugs in production.

  1. Error Detection and Debugging

TypeScript’s compile-time checks prevent common errors such as typos or incorrect property access.

JavaScript Example:

Picture3

TypeScript Example:Picture4

  1. Better Code Maintainability

Imagine working on a large project with multiple team members. How would you ensure everyone follows a consistent data structure? TypeScript helps with constructs like enums and interfaces.

Example:

Picture5

Using enums and interfaces, developers can clearly define and enforce constraints within the codebase.

  1. Backward Compatibility

TypeScript compiles to plain JavaScript, meaning you can gradually adopt TypeScript in existing projects without rewriting everything. This makes it an ideal choice for teams transitioning from JavaScript.

 

Common Misconceptions About TypeScript

“TypeScript is Too Verbose”

It might seem so at first glance, but have you considered how much time it saves during debugging? For example:

Picture6

“It Slows Down Development”

The time spent defining types is often outweighed by the time saved debugging and refactoring.

 

When to Use TypeScript?

TypeScript is particularly beneficial for:

  • Large-scale applications: It ensures maintainability as the project grows
  • Collaborative projects: Static typing helps teams understand each other’s code more easily.
  • Complex data structures: For simplification of complex data structures, TypeScript is a better approach.

Conclusion

While JavaScript comes as a handy and excellent language for many projects, TypeScript addresses its flaws by introducing static typing, improved tooling and better readability and maintainability. For developers looking to build a high scale application with error-resistant code, TypeScript would be a great choice.

]]>
https://blogs.perficient.com/2025/01/20/why-choose-typescript-over-javascript/feed/ 0 375901
How Copilot Vastly Improved My React Development https://blogs.perficient.com/2025/01/08/how-copilot-vastly-improved-my-react-development/ https://blogs.perficient.com/2025/01/08/how-copilot-vastly-improved-my-react-development/#respond Wed, 08 Jan 2025 18:37:01 +0000 https://blogs.perficient.com/?p=375355

I am always looking to write better, more performant and cleaner code. GitHub Copilot checks all the boxes and makes my life easier. I have been using it since the 2021 public beta, the hype is real!

According to the GitHub Copilot website, it is:

“The world’s most widely adopted AI developer tool.”  

While that sounds impressive, the proof is in the features that help the average developer produce higher quality code, faster. It doesn’t replace a human developer, but that is not the point. The name says it all, it’s a tool designed to work alongside developers. 

When we look at the stats, we see some very impressive numbers:

  • 75% of developers report more satisfaction with their jobs 
  • 90% of Fortune 100 companies use Copilot 
  • With 55% of developers prefer Copilot 
  • Developers report a 25% increase in speed 

Day in the Life

I primarily use Copilot for code completion and test cases for ReactJS and JavaScript code.

When typing predictable text such as “document” in a JavaScript file, Copilot will review the current file and public repositories to provide a context correct completion. This is helpful when I create new code or update existing code. Code suggestion via Copilot chat enables me to ask for possible solutions to a problem. “How do I type the output of this function in Typescript?”  

Additionally, it can explain existing code, “Explain lines 29-54.” Any developer out there should be able to see the value there. An example of this power comes from one of my colleagues: 

“Copilot’s getting better all the time. When I first started using it, maybe 10% of the time I’d be unable to use its suggestions because it didn’t make sense at all. The other day I had it refactor two classes by moving the static functions and some common logic into a static third class that the other two used, and it was pretty much correct, down to style. Took me maybe thirty seconds to figure out how to tell Copilot what to do and another thirty seconds for it to do the work.” 

Generally, developers dislike writing comments.  Worry not, Copilot can do that! In fact, I use it to write the first draft of every comment in my code.  Copilot goes a step further and writes user tests from the context of a file — “Write Jest tests for this file.”  

One of my favorite tools is /fix– which provides an attempt to resolve any errors in the code. This is not limited to errors visible in the IDE. Occasionally after compilation, there will be one or more errors. Asking Copilot to fix these errors is often successful, even though the error(s) may not visible. The enterprise version will even create commented pull requests! 

Although these features are amazing, there are methods to get the most out of it. You must be as specific as possible. This is most important when using code suggestions.

If I ask “I need this code to solve the problem created by the other functions” — I am not likely to get a helpful solution. However, if I ask “Using lines 10 – 150, and the following functions (a, b, and c) from file two, give me a solution that will solve the problem.”

It is key whenever possible, to break up the requests into small tasks. 

Copilot Wave 2 

The future of Copilot is exciting, indeed. While I have been talking about GitHub Copilot, the entire Microsoft universe is getting the “Copilot” treatment. In what Microsoft calls Copilot Wave 2, it is added to Microsoft 365.  

Wave 2 features include: 

  • Python for Excel 
  • Email prioritization in Outlook 
  • Team Copilot 
  • Better transcripts with the ability to ask Copilot a simple question as we would a co-worker, “What did I miss?”  

The most exciting new Copilot feature is Copilot Agents.  

“Agents are AI assistants designed to automate and execute business processes, working with or for humans. They range in capability from simple, prompt-and-response agents to agents that replace repetitive tasks to more advanced, fully autonomous agents.” 

With this functionality, the entire Microsoft ecosystem will benefit. Using agents, it would be possible to find information quickly in SharePoint across all the sites and other content areas. Agents can autonomously function and are not like chatbots. Chatbots work on a script, whereas Agents function with the full knowledge of an LLM. I.E. a service agent could provide documentation on the fly based on an English description of a problem. Or answer questions from a human with very human responses based on technical data or specifications. 

There is a new Copilot Studio, providing a low code solution allowing more people the ability to create agents. 

GitHub Copilot is continually updated as well. Since May, there is a private beta for Copilot extensions. This allows third-party vendors to utilize the natural language processing power of Copilot inside of GitHub, a major enhancement jumping Copilot to GPT-4o, and Copilot extensions which will provide customers the ability to use plugins and extensions to expand functionality. 

Conclusion

Using these features with Copilot, I save between 15-25% of my day writing code. Freeing me up for other tasks. I’m excited to see how Copilot Agents will evolve into new tools to increase developer productivity.

For more information about Perficient’s Mobile Solutions expertise, subscribe to our blog or contact our Mobile Solutions team today!

]]>
https://blogs.perficient.com/2025/01/08/how-copilot-vastly-improved-my-react-development/feed/ 0 375355
Leveraging WebSockets for Real-Time Data in React Applications https://blogs.perficient.com/2024/12/27/leveraging-websockets-for-real-time-data-in-react-applications/ https://blogs.perficient.com/2024/12/27/leveraging-websockets-for-real-time-data-in-react-applications/#respond Fri, 27 Dec 2024 12:40:17 +0000 https://blogs.perficient.com/?p=374592

In the modern web, real-time data has become a cornerstone of interactive and dynamic applications. WebSockets offer an effective solution for enabling real-time communication between the client and server, facilitating instant updates without relying on repetitive requests. In this blog, we’ll explore how to leverage WebSockets in React applications to deliver engaging, real-time experiences.

What Are WebSockets?

WebSockets are a protocol designed for two-way communication over a single TCP connection, allowing the server and client to exchange data seamlessly and in real time.

Benefits of WebSockets:

  • Low latency communication
  • Reduced network overhead compared to polling
  • Bi-directional data flow

 

Setting Up WebSockets in React

 

Step 1: Create a WebSocket Connection

React makes it straightforward to manage WebSocket connections, utilizing the WebSocket API to establish and handle interactions efficiently.

import React, { useEffect, useState } from 'react';


const WebSocketDemo = () => {

  const [messages, setMessages] = useState([]);


  useEffect(() => {
    const socket = new WebSocket('wss://example.com/socket');

    socket.onopen = () => {
      console.log('WebSocket connected');
      socket.send(JSON.stringify({ event: 'subscribe', data: 'initial' }));
    };


    socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      setMessages((prev) => [...prev, data]);
    };


    socket.onclose = () => {
      console.log('WebSocket disconnected');
    };
    return () => socket.close(); // Cleanup on component unmount
  }, []);

  return (
    <div>
      <h2>Real-Time Messages</h2>
      <ul>
        {messages.map((msg, index) => (
          <li key={index}>{msg.text}</li>
        ))}
      </ul>
    </div>
  );
};

export default WebSocketDemo;

 

Explanation:

  • The useEffect hook initializes the WebSocket connection when the component mounts and cleans it up when the component unmounts.
  • onopen sends an initial subscription message to the server.
  • onmessage listens for incoming messages, parses them, and updates the messages state.
  • onclose logs a disconnection message, and the cleanup function ensures the WebSocket connection is closed properly.

Step 2: Handle Reconnection Logic

WebSocket connections may drop due to network issues. Implement a reconnection strategy to maintain a seamless user experience.

const reconnectWebSocket = (url, attempts = 5) => {
  let retries = 0;
  const connect = () => {
    const socket = new WebSocket(url);
    socket.onclose = () => {
      if (retries < attempts) {
        retries++;
        setTimeout(connect, 2000); // Retry after 2 seconds
      } else {
        console.error('Failed to reconnect WebSocket');
      }
    };
    return socket;
  };
  return connect();
};

 

Explanation:

  • The reconnectWebSocket function manages reconnection attempts when the WebSocket closes unexpectedly.
  • A maximum number of attempts is specified to prevent infinite retries.
  • The setTimeout method introduces a delay between reconnection attempts, helping to handle transient network issues.

Real-Time Features to Implement

  1. Live Notifications: Keep users updated with real-time alerts or updates.
  2. Live Chat: Enable instant messaging within applications.
  3. Data Feeds: Provide live data streams, such as stock prices or sports scores.

Best Practices

  • Secure Connections: Always use wss:// for secure WebSocket connections.
  • Efficient Message Handling: Optimize data payloads to reduce bandwidth usage.
  • Graceful Error Handling: Provide fallback mechanisms in case of connection failures.
  • Server-Side Management: Ensure the server handles WebSocket connections efficiently to prevent resource exhaustion.

Conclusion

WebSockets are an excellent choice for building real-time features in React applications. By understanding how to set up, manage, and optimize WebSocket connections, you can deliver dynamic and engaging user experiences. Start integrating WebSockets into your React projects today to unlock the full potential of real-time communication.

Happy coding!

 

]]>
https://blogs.perficient.com/2024/12/27/leveraging-websockets-for-real-time-data-in-react-applications/feed/ 0 374592
State Persistence in Recoil using Local Storage https://blogs.perficient.com/2024/12/26/state-persistence-in-recoil-using-local-storage/ https://blogs.perficient.com/2024/12/26/state-persistence-in-recoil-using-local-storage/#respond Thu, 26 Dec 2024 08:20:02 +0000 https://blogs.perficient.com/?p=374433

Ever wish your app could remember things like a user’s theme choice, preferences, or other settings, even after a page reload? Good news: it absolutely can!

With Recoil, your trusty state management tool, and localStorage, the browser’s built-in memory, you can easily persist your app’s state. That means no more resetting the theme or losing data when users refresh or come back later.

And the best part? You don’t need anything complicated. just a few lines of code with Recoil and localStorage. It’s so easy, you’ll wonder why you didn’t do it sooner!

This small tweak makes your app seamless and user-friendly, like it has a memory that syncs with your users.

Ready to add persistence to your app with Recoil? Let’s get started!

First, check out my other blogs on Recoil to get a solid foundation. I cover basics like Recoil Intro Part and Recoil Hooks to help you get the most out of Recoil.

 

Main Advantages of Implementing State Persistence in Recoil with Local Storage –

Key benefits of persistence in recoil

Coding Example:

Let’s Implement the State Persistence in Recoil with Local Storage for Theme Preference

state.js –

import { atom } from 'recoil';

// Atom to store the mode (light or dark)
export const modeState = atom({
  key: 'modeState',  // Unique ID for the atom
  default: 'light',  
});

App.js-

import React, { useEffect } from 'react';
import { useRecoilState } from 'recoil';
import { modeState } from './state';

const App = () => {
  const [mode, setMode] = useRecoilState(modeState);

  // Load mode from localStorage
  useEffect(() => {
    const savedMode = localStorage.getItem('modeState');
    if (savedMode) {
      setMode(savedMode); // Set the mode if found in localStorage
    }
  }, [setMode]);

  // Save mode to localStorage whenever it changes
  useEffect(() => {
    localStorage.setItem('modeState', mode);
    document.body.className = mode; // Apply the mode to the body class
  }, [mode]);

  return (
    <div>
      <h1>Current Mode: {mode}</h1>
      <button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
        Change Mode
      </button>
    </div>
  );
};

export default App;

Index.js –

import React from 'react';
import ReactDOM from 'react-dom';
import { RecoilRoot } from 'recoil';
import './index.css';
import App from './App';

ReactDOM.render(
  <RecoilRoot>
    <App />
  </RecoilRoot>,
  document.getElementById('root')
);

index.css-

/* Default light mode */
body.light {
  background-color: white;
  color: black;
}

/* Dark mode */
body.dark {
  background-color: #121212;
  color: white;
}

button {
  padding: 10px 20px;
  cursor: pointer;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 5px;
}

button:hover {
  background-color: #0056b3;
}

Explanation:

This app saves and loads the theme from localStorage, and the mode can be toggled between light and dark.

  1. State Management: The modeState atom in Recoil stores the current mode (light or dark).
  2. Persistence: On page load, the app checks localStorage for the saved mode. If found, it applies the saved mode. When the mode changes, it is saved back to localStorage.
  3. Mode Toggle: A button toggles between light and dark modes, updating the background color and saving the mode to localStorage.
  4. Page Refresh: The selected mode persists across page refreshes, maintaining the last chosen theme.

 

Output:

 

Output

  1. When the app loads, it checks localStorage for a saved mode (light or dark) and uses it. If no mode is found, it defaults to light mode.
  2. Clicking the “Change Mode” button switches between light and dark modes and changes the background color.
  3. The app saves the selected mode to localStorage whenever it changes.
  4. When you refresh the page, the app gets the saved mode from localStorage and uses it, keeping the same mode.

 

In Inspect Mode (Developer Tools), go to the Application tab to see localStorage entries where the light/dark mode is saved. When the mode is toggled, the localStorage value updates with the new mode. After refreshing the page, the saved mode is retrieved from localStorage and applied, which you can verify by checking both localStorage and the body class in the Elements tab.

Inspect mode persistence

In short, using Recoil with localStorage saves user settings like the theme here between sessions and page reloads, making the experience more consistent and personalized.

Conclusion:

Using Recoil with localStorage is a win-win for both users and developers. For users, it means their preferences, like the theme, are saved across sessions, making the experience feel seamless and personalized every time they return. For developers, it takes the hassle out of managing state persistence. With Recoil handling the app’s state and localStorage automatically saving settings, developers can focus on building excellent features instead of worrying about saving and loading data. This combination makes the development process smoother, faster, and more efficient.

That’s a wrap for today! But don’t go too far. I’ll be diving into tools and techniques that make development easier and more exciting. Until then, keep experimenting, stay curious, and happy coding!

]]>
https://blogs.perficient.com/2024/12/26/state-persistence-in-recoil-using-local-storage/feed/ 0 374433