Handle Custom Input with useImperativeHandle

Understanding useImperativeHandle with example


React chooses rendering UI based on props and state, it is also called declarative UI. There is another approach, imperative, that is useful when your program requires more fine-grow control over data flow. In this article, I'll explain how we can use the Imperative method to deal with data flow.

In React, you define steps to manipulate DOM to update node elements. React provides refs to directly access the DOM, but refs expose the element node or component itself. React introduces useImperativeHandle hook, which exposes its own specific functions and native properties outside of the child component. 

useImperativeHandle 

You can call the useImperativeHandle hook on the child component to define properties and methods that should be accessible from a parent component. 

It takes two arguments, ref which you get from forwardRef, and handler function, which returns mostly objects with a group of all properties or methods you want to expose. You can also use dependencies array but it's optional.


useImperativeHandle(ref, () => {
  return { } 
}) 

The useImperativeHandle only works in combination with forwardRef.

Form validation 

Let's say you have a child component called Input that contains a validation function. You want to allow the parent component to imperatively check validation on email. Here is how you can use useImperativeHandle in functional component.

import {
   forwardRef,
   useRef, 
   useState, 
   useImperativeHandle } from 'react'

const Input = forwardRef(({label, id, ...props}, ref) => {
  const emailRef = useRef(null)

  const [error, setError] = useState(null)

  const validateInput = () => {
    const enteredEmail = emailRef.current.value
     if (enteredEmail === '' && !enteredEmail.includes('@')) {
      setError('Please Enter valid email address')
      } else {
        setError(null)
      }
    }
    // expose validateInput function to parent component
    useImperativeHandle(ref, () => {
      return {
        validate: validateInput
      }
    })

    return (
      <div>
        <label htmlFor={id}>{label}</label>
        <input id={id} { ...props } ref={emailRef} />
        { error && <p style={{color: 'beige', textShadow: '0 0 2px #ccc'}}>{error}</p> }
      </div>
    )
  })

export default Input


The validateInput function shows an error if the input field is empty or email address doesn't contain @ symbol. 

The useImperativeHandle allows the Input component to expose the validate function to its parent component, which may then be used to validate the form before submission. The ref objects allow the parent component to interact directly with the child component.

import classes from './SubscriptionForm.module.css'
import Input from "./Input"

import { useRef } from "react"

const SubscriptionForm = () => {
  const inputRef = useRef(null)
  
  function handleSubmitForm(event) {
    event.preventDefault()

    if (inputRef.current) {
      inputRef.current.validate()
    }
  }
 
  return (
    <form onSubmit={handleSubmitForm}>  
      <Input 
        label="Email" 
        type="email"
        id="email"
        ref={inputRef}
         />
      <button>Subscribe</button>
    </form>
  )
}

export default SubscriptionForm

Here we used useRef hook to create a reference to the Input component. The parent component called `inputRef.current.validate()` function imperatively to interact with the input. The parent maintains control over validating the form but doesn't need to manage the underlying <input> DOM node.

Conclusion

When the useImperative hook is combined with forwardRef, the ref object exposes a custom value rather than forwarding to input.

You will use useImperativeHandle rarely but in some cases, this hook can be very helpful like focusing a node, exposing custom value, level of control, direct interaction, or third-party integration.


Different Between useMemo and useCallback

Compare difference between useMemo and useCallback, their use cases and important features


As a core developer, when you construct an application, you consider not just how beautiful the user interface is, but also how smoothly it runs, how quickly it loads, and how fast it is. To accomplish this, we need a memoization technique.

React has two essential hooks: usecallback and usememo. Both hooks are used for function optimization and return memoized result. They both are useful in memoization but it can be difficult to determine which hook is more suitable to which condition because typically they give you similar solutions on different values.

In this tutorial, I'll clarify any confusion so you can confidently use them in your project.

Let's see the example:

Find Factors of numbers

Let's suppose we've a Factorial Calculator to find out factors of numbers. A factor is a number that divides with no remainder.

import styles from './Factoring.module.css'
import Button from './Button'
import { useState } from 'react'

const Factoring = () => {
  const [number, setNumber] = useState(0)
 
  let factors = []
  for (let i=1; i<=number; i++) {
    if (number % i === 0) {
      factors = [...factors, i]
    }
  }
  const factorChange = (event) => {
    setNumber(parseInt(event.target.value))
  }
  const handleClearInput = () => {
    setNumber(0)
  }
  
  return (
    <div className={styles.factoring}>
      <div className={styles["factoring-calct"]}>
        <h1>Factoring Calculator</h1>
        <p>Find the Factors of:</p>
        <div>
          <input type="number" value={number} onChange={factorChange} />
          <Button className={styles.clearInput} label="Clear" onClick={handleClearInput} />
        </div>
        <div>
          <h3>Factors of {number}</h3>
          <span>Answer: {factors.join(', ')}</span>
        </div>
      </div>
    </div>
  )
}

export default Factoring

  • I used state to manage factors where number is a user-specified value.
  • Using a for loop to calculate factors that iterate from 1 to specified number.
  • A function to reset number state,
  • We render a number input and a Button child component to clear Input.

Following are reusable Button Component:

import { memo } from "react"

const Button = memo(({label, ...props}) => {
  console.log('Button is child component')
  return (
    <button {...props}>{label}</button>
  )
})

export default Button

In this Button component I used memo function to prevent unnecessary re-rendering of child component.

If factorial calculator solve a large numbers of calculation to find factors then the whole component will pause until it is done but sometimes we don't need to perform this calculation.

Let's suppose I'm running a countdown inside the component, and we have a state to update the countdown number every second, this would cause a performance problem because the component would repeatedly render, rerun expensive calculations, and recreate functions upon each state update.

It will also force the Button component to re-render every second, even though we are using the memo function. Becuase we are passing function onClick={handleClearInput} to the child component, memo function won't work. If you're curious about why check out useCallback complete guide.

Skip Calculations: useMemo vs useCallback

React provides various ways to implement memoization. It is particularly useful when dealing with computationally expensive or frequently called functions

The question is: which one? Let's see one by one.

useMemo

The useMemo memoizes values. The useMemo hook is very handy for expensive computations. When you declare time-consuming functions and perform complex operations like huge data filtering or sorting algorithms, you can use useMemo hook to memoize the result.

const factorize = useMemo(() => {
    let factors = []
    for (let i=1; i<=number; i++) {
      if (number % i === 0) {
        factors = [...factors, i]
      }
    }
    return factors
  }, [number])
  
  <span>Answer: {factorize.join(', ')}</span>
  

If its inputs are the same as its dependencies have not changed, useMemo hook returns cached results.

useCallback

The useCallback memoizes the callback functions themselves. usecallback works exceptionally well with event handlers, especially when dealing with child components. 

It creates a function reference and then on each render it returns the same function reference as long as its dependencies have not changed. 

const handleClearInput = useCallback(() => {
    setNumber(0)
  }, [])

Impact on re-rendering

  • useMemo does not directly control component re-render itself, it plays a crucial role in optimizing specific parts by memoizing the results.
  • usecallback simply ensures that the child component does not re-render unnecessarily due to changes in the parent component's state.

Key use cases:

  • useMemo is most effective for expensive computation within the component. It essentially caches the output of a function to avoid redundant calculations if the dependencies haven't changed.
  • usecallback can be particularly beneficial when dealing with child components. It optimizes event handlers passed but does not affect the logic.

Conclusion

React checks referential equality for both, although useMemo is used for values and useCallback is given for functions.

useMemo can be used to memoize the output of a computation or to prevent the re-calculation. On the other side, you can use useCallback to avoid function re-creation.

React useCallback Hook Complete Guide

understanding usecallback with example code and case study


Memoization is an essential feature in web development as it can increase the performance of our website. React also knows it, that's why React gives us different features to use for optimization which is catching the result in memory and preventing unnecessary load on the application.

In these memoize techniques I'm sure you have seen useCallback hook in many projects. But do you really know the basic idea behind it or should you use it more often? I will explain it deeply so you'll understand it better.

Case Study

You can define useCallback as a function memoization technique but this definition alone can't explain anything. Let's explore it.

For this tutorial, I prepared a very basic demo application. It's a basic search functionality and also a button to change the theme color of the list of books.

import { useState} from "react";

import { getRandomColor } from "./utils";
import SearchBook from "./SearchBook";

const Famous_Books = [
  'Romeo and Juliet',
  'Pride and Prejudice',
  'Anandmath',
  'Hard Times',
  'Audacity of Hope',
  'Treasure Island',
  'Robinson Crusoe'
];

const BookApp = () => {
  const [books, setBooks] = useState(Famous_Books);
  const [themeColor, setThemeColor] = useState('#333333')

  function handleSearch(searchTerm) {
    const searchBooks = books.filter(book => book.toLowerCase().includes(searchTerm.toLowerCase()));
    setBooks(searchBooks);
  }

  function handleThemeColor() {
    setThemeColor(getRandomColor())
  }

  return (
    <div>
      <h1>Famous Books</h1>
      <div>
        <SearchBook onSearch={handleSearch} />
        <button type="button" onClick={handleThemeColor}>
          Change Theme
        </button>
      </div>
      <ul>
        {books.map((book) => <li style={{ color: themeColor}} key={book}>{book}</li>)}
      </ul>
    </div>
  );
};

export default BookApp;

useCallback example  -- search filter


  • I registered two states: one with the default theme color and the other with the Famous_books array as the initial value, which contains a list of book titles.
  • I declared event handler functions so items should render based on events.
  • The handleSearch function filters books based on text input and should only keep matching items and drop other items in the array. The handleThemeColor function changes the theme colour of a list of books.

In JSX I return SearchBook component, the code is as follows:

const SearchBook = ({ onSearch }) => {
  console.log('re-render child component')
  return (
    <input
      type="text"
      placeholder="Enter Book name"
      onChange={(event) => onSearch(event.target.value)}
        />
  )
}

The SearchBook component receives onSearch properties from the parent component and passes the input value to the parent component's handleSearch function.

Now when you search or click on the theme change button you'll see the child component being re-render. Though it's not a huge problem to be re-render because it's a very basic app and contains very little code, still we can optimize it. 

hwo to prevent child component to re-render by using usecallback?


To avoid redundant rendering of the child component when its parent changes, we could wrap the SearchBook component with the memo(). Basically, it returns memoized functional components.

import { memo } from 'react'

const SearchBook = memo(({ onSearch }) => {
  console.log('re-render child component')
  return (
    <input
      type="text"
      placeholder="Enter Book name"
      onChange={(event) => onSearch(event.target.value)}
        />
  )
})

Now after that when you click on the theme button, in Dev Tool you'll notice this strange behavior; it still re-renders the child component, SearchBook.

So what happened here? Is there a problem with the memo function? Let's again look at the memo function definition.

The Memo function compares the previous props value to the current props value and only executes the memoize component again if the props are not the same as the prior render.

Let's look at the props. The searchBook component receives the onSearch prop, which accepts a function as a value. 

const SearchBook = ({ onSearch }) => { }

According to the memo function definition, the onSearch property changes every time the parent component is re-rendered. But why is such behavior occurring?

When to use useCallback?

When a component function runs or re-renders, all of the code inside that component is likewise run, causing the state to registered again, the function to be regenerated, and the JSX code to run once more.

In Javascript, when you compare strings, it returns true.

 "react" === "react" // true 

When you compare numbers, it returns true.

 30 === 30 // true 

But when you compared functions will return false

 () === () // false

The comparison of Objects will also return false because two objects created with the same code are not equivalent.

{} === {} // false 

In JavaScript, functions are just values, or as we can say, objects. So in React when component function is re-render a new function object is re-created.

As a result, when the BookApp component re-renders, a new handleSearch function is created, which is why the function prop is not recognized as equal, and the onSearch prop in the search book component varies between render cycles.

When React compares this new render value to the previous render props value, it notices that they are not the same, which is why memo function optimization will not work here; it will re-execute the child component even if the props remain unchanged.

useCallback

For this complex problem, React gives us a simple solution, We can stop re-execution of the function by using useCallback hook.

useCallback(callback, dependency)

The useCallback hook returns the memoize function and runs it only if one of the dependencies changesIt is especially useful when a function is passed down to a child component as a prop to maximize productivity.

The useCallback accept function that we want to memoize as a first argument and an external variable `books` which this function depends on, a dependency, as a second argument.

useCallback returns the function that you wrapped; you can give the same name as your function name.

const handleSearch = useCallback(function handleSearch(searchTerm) {
    const searchBooks = books.filter(book => book.toLowerCase().includes(searchTerm.toLowerCase()))

    setBooks(searchBooks)
  }, [books])

An empty dependency array may be used in cases where the function depends on no external variables.

By wrapping function with useCallback we prevent the function object from being re-created each time its parent component executes, allowing to use of the same function between renders.

Now that useCallback has memoized the handleSearch function, the SearchBook component will no longer render.

Optimizing callback in useEffect

In other cases, we can optimize callback in Effect. Let's say I need to build a network connection that has side effects, so I'll utilize useEffect.

function fetchData() {
    // connect...
  }

  useEffect(() => {
    fetchData()
  }, [fetchData])

I've provided the function fetchData as a dependency array. As we all know, if any code inside of Effect depends on an external source, it must be included as a dependency array. The issue arises when we pass a function as a dependency since it can cause us to become trapped in an endless loop.

When you add a dependency array, you notify React that Effect method should execute whenever the dependency value changes.

As we know when a component function is re-executed, it creates a new function object and React uses it as a new value. When a prop function receives a new value, React compares the two values to determine that these two are different.

It will cause your Effect to call the function repeatedly, and it will cause your application to break.

To fix this, wrap the function you need to call from an Effect into useCallback:

const fetchData = useCallback(function fetchData() {
    // connect...
  }, [])

  useEffect(() => {
    fetchData()
  }, [fetchData])

useCallback Best Practice

It's easy to use and fixes performance issues, but should you use the useCallback hook for every event handler? The answer is a big NO!

You should only utilize this hook for performance reasons, such as avoiding unnecessary rendering and optimizing callbacks in useEffect. Be careful not to misuse it.

Conclusion

The useCallback store function itself and returns memoize functions. in this article, I demonstrated search functionality so you can understand function optimization better and the idea behind using it.

it's a very important feature of React but don't overdo it because it won't benefit you in any way, but will instead harm web performance and cause problems. 

I also write an article about useMemo hook to improve app performance. This gives you the same solution but for a different problem. 

Stop Re rendering Child Component with React memo()

Memoize component with memo react for load app faster


React executes the component whenever the state, context, and props value change, but do you know every time the parent component updates, its nested components will also re-evaluate. 

Which is normal behavior of React. However, if the child component contains heavy calculation or large data management then it would negatively affect the performance of the parent component even if update won't have anything to do with child components. 

In this case, if you don't want to re-render a child component, you can utilize React's built-in method memo function.

In this article, I will discuss component optimization and how to prevent a child component from re-rendering when its parent component is updated.

React memo()

Memo function is a built-in performance optimization technique that is used to memoize the result of the component. It returns the cached result when the same output occurs again and speeds up the execution.

It will keep track of the previous prop's value and compare it with the current value. If it detects changes, it will only execute the child component again and re-evaluate it; if not, it will not execute it at all.

Let's see why the memo function is essential before I go over how to utilize it.

I have a simple application, a list of tabs and when I switch tabs it renders the corresponding content. 

import ActiveTasks from "./components/ActiveTasks"
import AllTasks from "./components/AllTasks"
import CompletedTasks from "./components/CompletedTasks"
import TabBtn from "./components/TabBtn"

import { useState } from "react"

function App() {
  const [activeTab, setActiveTab] = useState('all')
  const [newTask, setNewTask] = useState('')

  const handleClick = (tabName) => {
    setActiveTab(tabName)
  }
  const handleNewTaskChange = (e) => {
    setNewTask(e.target.value)
  }
  return (
    <section className="tasks">
      <label>New Task</label>
      <input value={newTask} type="text" onChange={handleNewTaskChange} />
      <menu>
        <TabBtn onClick={() => handleClick('all')} activeId={activeTab === 'all'}>All</TabBtn>
        <TabBtn onClick={() => handleClick('completed')} activeId={activeTab === 'completed'}>Completed</TabBtn>
        <TabBtn onClick={() => handleClick('active')} activeId={activeTab === 'active'}>Active</TabBtn>
      </menu>
      <div>
        {activeTab === 'all' && <AllTasks title="User Tasks" />}
        {activeTab === 'completed' && <CompletedTasks title="Completed Tasks" />}
        {activeTab === 'active' && <ActiveTasks title="Active Tasks" />}
      </div>
    </section>
  )
}

export default App; 

In the following code, we used state to change the UI, and I have three nested components within the App component, where I'm passing props title to those child components.

const AllTasks = ({title}) => {
  console.log('<AllTasks />')
  return (
    <div className="title">{title}</div>
  )
}

const CompletedTasks = ({title}) => {
  console.log('<CompletedTasks />')
  return (
    <div className="title">{title}</div>
  )
}

const ActiveTasks = ({title}) => {
  console.log('<ActiveTasks />')
  return (
    <div className="title">{title}</div>
  )
}

Now when I click the button, React will re-execute that component and Ui will update information based on the selected tab. In every child component I've passed console so every time it re-renders, it'll log the message to console.

Inside the App component, I also have an input field where due to state changes, every letter will force the App component to re-render, however every time the parent component is updated, the child components will also be re-rendered, even if they are not required.

In small applications it's okay because React will execute in an instant but what if one of child component contains expensive calculations. 

import { utils } from '../utils'

const CompletedTasks = memo(({title}) => {
  const expensiveCalculaion = utils()

  console.log('<CompletedTasks />')
  return (
    <div className="title">{title}</div>
  )
})

export default CompletedTasks 

Here utils() function will loop over billions of numbers every time child component re-render, therefore every letter of input field will take a moment to render even though the input field is unrelated to the child component

Use React memo() in component

To memoize a component wrap CompletedTasks component or any other child arrow functional component with memo. Also you need to import memo method from react library.

Now our CompletedTasks component will look like this;

import { utils } from '../utils'

import { memo } from 'react'

const CompletedTasks = memo(({title}) => {
  const expensiveCalculaion = utils()

  console.log('<CompletedTasks />')
  return (
    <div className="title">{title}</div>
  )
})

Memo function only applies to its parent component and child component will still run if its own state or context change. 

Now let's change the props title value to `All completed tasks`.

<CompletedTasks title="All Completed Tasks" />

React will notice the changes and re-render the child component. The UI will be updated with new props, and the console will be run again.

Avoid using memo() function unnecessarily

Memo function also has some downside and it's recommended to not use it everywhere. Whenever parent executes, React performs a comparison for child component.

To avoid that circumstance we can use some technique.

  • You can wrap higher root component with memo function so it'll take care of all nested child components.
  • Avoid using memo function if props are going to change on every execution.
  • If React application is small and doesn't contain expensive calculation then don't perform memoization.
  • Profile parent component and adjust some code.to minimize props change.

Conclusion

React memo() function plays a crucial role in application optimization. it returns same cached output as long as props haven't changed and prevents unnecessary re-rendering.

React Performance with useMemo

Explanation of useMemo and how to use useMemo in component


In this article you'll understand useMemo() and learn how to improve your react application's performance.

Sometimes, React must do expensive calculations, such as filtering massive amounts of data or running billions of cycles, which might cause React applications to render slowly. 

This is where useMemo hook comes in handy, which is used to optimize react applications.

useMemo

The useMemo is another essential built-in hook in React that comes in handy when we create a production-ready React application. The primary reason to use useMemo in our components is for better performance.

Technically, useMemo caches results and saves the output of calculations between renderings. As a result, you can expedite the application by avoiding recalculation when the component is loaded.

Unnecessary Calculations

Suppose I've built a React application that renders a set of tabs and when I switch tabs it updates the UI with their corresponding content and I also I’ve an input field.

import TabBtn from "./TabBtn"
function App() {
  const [activeTab, setActiveTab] = useState('all')
  const [newTask, setNewTask] = useState('')
  
  const handleClick = (tabName) => {
    setActiveTab(tabName)
  }
  const handleNewTaskChange = (e) => {
    setNewTask(e.target.value)
  }
  return (
    <section className="tasks">
      <label>New Task</label>
      <input value={newTask} type="text" onChange={handleNewTaskChange} />
      <menu>
        <TabBtn onClick={() => handleClick('all')} activeId={activeTab === 'all'}>All</TabBtn>
        <TabBtn onClick={() => handleClick('completed')} activeId={activeTab === 'completed'}>Completed</TabBtn>
        <TabBtn onClick={() => handleClick('active')} activeId={activeTab === 'active'}>Active</TabBtn>
      </menu>
      <ul>
        {activeTab === 'all' && <li>All Tasks</li>}
        {activeTab === 'completed' && <li>Completed Tasks</li>}
        {activeTab === 'active' && <li>Active Tasks</li>}
      </ul>
    </section>
  )
}

To choose a tab and bind an input field, I used the useState hook. The component is going to re-render the application when the state changes or updates.

I've got another file named utils.js. This file contains a function called utils and this utils function performs expensive operations.

// utils.js
export const utils = () => {
  let tasks = [];
  for (let i = 0; i < 1000000; i++) {
    tasks.push({
      id: i + 1
    });
  }
  return tasks;
}

Now let's call utils function inside the App so I can artificially slow down my application.

// App.js
const expensiveCalculation = utils()

In the browser when you switch tabs you'll see it taking a small pause during rendering and also when you type into the input field it takes a while before the letter shows up.

As previously stated, React evaluates applications when state, props, and context change so each keystroke causes the state to update and re-render the component, and that will again cause the utils function to re-calculate the count or cycle through the loop over a million times before it settles. It would happen every time, even if the function produced the same result.

Here comes another essential hook useMemo() to optimize React application.

We use useMemo hook to memoize the output of a function. Instead of recalculating the result each time the components re-render, It stores the results of expensive functions and returns cached results.

How to use useMemo()

The useMemo hook accepts callback function and returns result of a function. As second argument, it takes its dependency and if calculation function has no dependency you can pass an empty array i.e. []

useMemo(() => {}, [])

To use useMemo() import it at the top of component.

import { useMemo() } from 'react 

Now we can wrap utils function with useMemo.
const expensiveCalculation = useMemo(() => utils(), [])

Now switch tabs and type into input fields; you’ll see application is fast.

Because of useMemo(), the expensiveCalculaition variable is now memoized, which guarantees that the utils function is only called once during initial rendering. This means that after the component renders for the first time, it won't recalculate until the dependencies change, and since there are no dependencies, the function won't re-execute.

Let's say that if I type anything in the input field, I want to call the utils method once again. I'll provide the newTask variable as a dependency.

const expensiveCalculation = useMemo(() => utils(), [newTask])

Now  React compares the current and previous dependencies; if a change occurs, then utils function will execute the calculation. Switching tabs is fine.

Don't overuse useMemo

Memorization can increase React performance, however it is best to avoid using useMemo while performing inexpensive operations. React will go out of its way to compare it on each execution, causing React to perform more work.

Additionally, if the computation changes or updates often, we don't want this behavior to occur. Before implementing memorizing in your application, I would advise you to thoroughly profile your component and evaluate various optimizations.

Conclusion

useMemo is a built-in React hook used for optimizing the performance of an application. useMemo memoize expensive calculations to skip recalculation. 

When it comes to performance issues useMemo() is one of the best options you can apply in react application. With the useMemo hook, you can store the result of a calculation or catch computation value and use it across multiple renderings.

React Ordering Web App with UI and Cart Functionality

Step-by-step guide to create a react simple drink ordering app and shopping cart for beginners


These days, ordering apps are more popular, especially since the outbreak of the pandemic, as they allow for the delivery of goods to your door from your preferred locations without the need to leave the house. So, let's add a Drink order app to our portfolio and resume, to make a significant impact. 

Simplifying Data Sharing in React with Context API: A Localisation example - part 21


A Complete Guide to Context API: Building a Localisation Project with React


We usually deal with the state and layer of components in typical React applications. Components are independent and reusable and accept props to communicate with each other. However, passing complex data between components can lead to confusing code and loss if you have to forward data through many components. 

useRef Hook: Secret Recipe of DOM Manipulation - part 18

Learn how to use useRef hook in react with example | elpeeda.net


 In the process of building a React application, you'll encounter a situation where you have the argue to touch the DOM element. For example, to implement a scroll to top button, to focus the input field, set the tooltip position, get element height and width, and so on, there could be many reasons and React provides one solution which is refs.

React works with a single React root Dom element, but it also opens the gate for escape hatches, so you can not only store information of Dom nodes but also manipulate it or work with browser API. You can also use refs for remembering information like the number of times a user tried to log in and you don't want to render this information.

This article is going to take as follows: 

  • How useRef works?
  • The useRef hook simple examples
  • Difference between useRef and useState
  • The useRef tips and best practices

What is useRef hook in React?

The useRef is a hook in React and is used for two main reasons.

  1. Access the DOM element that allows interaction with React components or HTML node elements directly.
  2. Store state or instance values, allow you to persist value across render.
We will learn both cases in detail with example code.

Creating a reference with useRef Hook

Refs is a short form of reference. To get real information about a DOM element we need to create a reference with the help of useRef hook.

Let's declare refs inside the functional component by importing useRef from react library.

import {useRef} from 'react'

useRef initial value null

We will add refs to the component and pass the initial value as an argument to useRef hook, in other words, the initial value can also refer as a placeholder. You can specify any data type as initial, like a number, string, boolean, object, or null.

It's not mandatory but it's a common practice in programming to use null or undefined as initial value. As the user should not interact with the DOM property during render, it'll lead to a behavior difficulty of component prediction; React predicts the outcome of a component based on its props and state.

Initializing the value null, undefined, or zero during render is best practice. 

const buttonRef = useRef(null)

Ref attribute in React 

The ref attribute is a built-in key prop. We can use the ref attribute on any HTML element in which we want the reference value of the DOM node to directly manipulate it or accept the state or props of a component.

Here, is an example of attaching the refs to a button using the ref attribute and storing the reference in the buttonRef constant.

<button type='button' ref={buttonRef} />

Current property and its use cases

The useRef hook returns the ref object with the special current property which holds the current reference values of the element. It's used to access the DOM elements or store instance values which help to maintain React applications.

You can use this current property to read the reference value with reference.current, and modify the current value with reference.current = updateValuewithout causing the component to re-render.

The current property also helps to call method ex-focus or browser API on the element and store the value of timer or event listener and update it as needed.

A simple example that demonstrates current property use to access the DOM element and call method on it.

import { useRef } from "react"
const Form = () => {
  const inputRef = useRef(null)
  const buttonRef = useRef(null)
  
  const handleInputChange = () => {
    buttonRef.current.disabled = inputRef.current.value === ''
  }
  
  return (
   <form>
      <input type='text' ref={inputRef} onChange={handleInputChange} />
      <button ref={buttonRef} disabled>Submit</button>
    </form> 
 )
}
export default Form

Here, we are referencing the input and button, it returns a mutable object with current props which we can read the value and modify by calling the disabled property on the button element.

Modify DOM node elements

In certain situations, we need to access the DOM element in React component and change the behavior of the HTML element which can't be done through state and props alone. For example, implementing custom form validation logic, modifying the properties or styles based on conditions, integrating with third-party libraries, or for some visual effects like animations.

Let's implement the scroll-to-top button that will demonstrate the usage of useRef hook for manipulating the DOM.

Creating a scroll-to-top Button with the useRef hook in React

I'll use scrollRef to store a reference to the scroll container and useState hook to store a boolean value to check the condition of whether the button should appear or not based on scroll position.

import { useState, useRef } from "react"
const ScrollToTop = () => {
  const scrollRef = useRef(null)
  const [disaplayButton, setDisplayButton] = useState(false)
  
  const handleScrollButton = () => {
    if (scrollRef.current.scrollTop > 100) {
      console.log('scrolled')
      setDisplayButton(true)
    } else {
      setDisplayButton(false)
    }
  }
  const handleScrollToTop = () => {
    if(scrollRef.current) {
      scrollRef.current.scrollTo({top:0, behavior:"smooth"})
    }
  }
  return (
    <div ref={scrollRef} style={{position: 'relative', height: '400px', overflow: 'scroll'}} onScroll={handleScrollButton}>
      <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sagittis lorem nec massa consequat, vel mattis
orci ullamcorper. Donec lacinia sapien id dolor consectetur, quis lobortis ex finibus. Integer ut ex et velit
      </p>
      { displayButton && 
        <button className="top-button" type="button" onClick={handleScrollToTop}>Top</button>
    </div>
  )
}
export default ScrollToTop

The handleScrollButton function checks the scroll position is greater than 100px and updates the function, the button will only show when the user has scrolled down past the value.

When the button is clicked, the handleScrollToTop function is triggered to scroll to the top position.

The onScroll event handles scrolling events on an element and is used to trigger the handleScroll function.

Make sure to specify the overflow property on the parent div element, set to scroll.

CSS file to style the scroll-to-top button and import this file into the ScrollToTop component at the top.

ScrollToTop.css
.top-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  background-color: #000;
  color: #fff;
  width: 50px;
  height: 50px;
  border-radius: 50%;
}
.top-button::before {
  content: '';
  position: absolute;
  border-right: 8px solid transparent;
  border-left: 8px solid transparent;
  border-bottom: 8px solid #fff;
  margin: -8px;
}

Usage useRef Hook for Persistent Data storage in React Components

The useRef Hook also stores referencing values that persist across re-renders. It stores values in memory and only updates when you modify it with the current property, which means data remain unchanged even after a component update or re-render due to some action.

Updating the reference values doesn't cause the component to update.

The useRef hook is useful when you want to store input value or scroll position in a constant that persists between renders and only changes when the reference values change.

Keeping track of the Previous value 

We can use referencing value technique to create a functionality that requires a history of previous values.

In this example we'll use the useRef hook to reference the previous value of the counter increases by 5, and we'll alert a message.

 import { useRef, useState } from "react"

 const Counter = () => {
   const [counter, setCounter] = useState(0)
   const prevCounterRef = useRef(0)

   const handleClick = () => {
     setCounter(counter + 1)
   }
   if (counter !== prevCounterRef.current && counter % 5 === 0) {
     alert('Counter increased by 5')
     prevCounterRef.current = counter
   }
   return (
     <>
       <h2>{counter}</h2>
       <button onClick={handleClick}>Increment</button>
     </>
   )
 }
 export default Counter

We reference the counter's previous value and compare it to the current value to generate an alert message if the current count is not equal to the previous value and is divisible by 5.

How useRef different from useState Hook?

  • Refs return mutable objects with the current property, allowing you to access and manipulate HTML element properties, whereas useState is treated as immutable and does not support the push or pop methods.
  • The useState hook manages stateful values that can change over time while useRef hook stores value that has to persist between renderings.
  • Changing state values causes components to re-render, but refs hold value in memory and have no effect on rendering.
UseState and useRef hooks each provide different functionality, but they can be used together to manage and maintain React components.

Tips and Best Practices for useRef Hook

Here are some points for enhancing user experience with useRef.

  • Prefix the variable name with refs, for example, buttonRef or inputRef. This helps to determine the variable store reference value.
  • You'll enjoy using the useRef hook, but don't overdo it; it's best to handle component functions in the React approach.
  • Somewhat useRef functionality matches the state but avoids refs for state management, as it doesn't trigger re-render.
  • The useRef is used to reference a DOM element, but you should not create a reference during rendering or manipulate DOM directly; instead, use useEffect or events handler to update reference data.

Conclusion

The useRef is one of the crucial hook that let you perform side effects in your react application, such as manipulating the DOM and creating persistent values without triggering the component to re-render, which enhances performance.

However, keep in mind that useRef is not a replacement for the state, so use it correctly and understand its limitations.

You can find more information about useRef hook on official document.

Referencing values with Refs 

Manipulating the DOM with Refs 

useRef

Top 8 Common Mistakes New React Users Make - part 15

← Toggle hide and show in Reactjs | display form on button click - part 14

React js - Look out fro these common mistakes as a beginner


Are you seeing red text or underlining in your text editor, terminal, or browser screen? If so, there may be a flaw in your code. Red is always a symbol for mistakes, whether it be on a student's notepad or a developer's code editor. Perhaps, as a result, border 1px red became a CSS debugging method. I'm unromantic please excuse me!

Toggle hide and show in Reactjs | display form on button click - part 14

React show and hide component based on state


I plan to add conditional rendering based on the state and update the App to reflect it. Make sure you are familiar with concepts related to React state Hook and props.

The job at hand is to entirely hide the form on the screen and have it only appear when the button is clicked and a new user submission is desired.

I've already shown how conditional rendering works in React; today I'll use one of the examples to show how conditional logic is applied to forms.

Display Form on Button Click

We have the UserForm inside the App component and have already created and worked with a form submission, I will apply all the logic inside the App file.

The addForm state variable and the state updating function setAddForm must first be registered in order to update the initial value of the useState() function, which by default returns the boolean value false.

const [addForm, setAddForm] = useState(false)

The form is dependent on the state; if it is false, it will not appear on the screen.

Now, in JSX, I'll add a condition using the javascript expression && to the UserForm component, and it will check the value of the addForm variable, and if it is false, it will not output the form.

function App() {
  const [addForm, setAddForm] = useState(false)
  return (
    <div className="App">
      {addForm && <UserForm onAddDetail={addDetailHandler} />}
      <MyComponent />
    </div>
  );
}

export default App;

However, if I set the initial value to true, the form will be output on the screen and the expression will be evaluated.

const [addForm, setAddForm] = useState(true)

What I'm looking for here is a toggle behavior when the button is pressed.

In the App component function, I'm going to declare the function displayForm, which will call the setAddForm function and update the default value.

I'm not going to specify the value manually, but instead set the value of variable addForm to the opposite value, which means that if the state value is false, it'll be true, but if it's true, it'll be false.

function App() {
  const [addForm, setAddForm] = useState(false)
  
  const displayForm = () => {
    setAddForm(!addForm)
  }
  return (
    <div className="App">
      {addForm && <UserForm onAddDetail={addDetailHandler} />}
      <MyComponent />
    </div>
  );
}

export default App;

Now we need to trigger that function if the user clicks the button, which happens to be inside the MyComponent file, so go to the JSX MyComponent element and pass the onAddForm and point to the function displayForm().

function App() {
  const [addForm, setAddForm] = useState(false)
  
  const displayForm = () => {
    setAddForm(!addForm)
  }
  return (
    <div className="App">
      {addForm && <UserForm onAddDetail={addDetailHandler} />}
      <MyComponent onAddForm={displayForm} />
    </div>
  );
}

export default App;

We have a button element inside of the MyComponent; we will listen for the onClick event and apply the props as a value to that element.

function MyComponent = (props) => {
  const className = props.active ? 'default' : 'active'
  
  return (
    <FancyBorder className="container">
      <button value='Happy coding' className={`${className} shape`} onClick={props.onAddForm}>Add List</button>
      {props.children}
    </FancyBorder>
  );
}

export default App;

If I click the button, the form will toggle exactly like that. Now that it toggles between, I want to dynamically alter the button color.

Change class name on click

I want to apply for a class based on conditions at this point. Using CSS styling, I'll modify the button's color based on its current state. 

We have java script code in our MyComponent file that uses ternary operators to target various style props so that you may classify this button as active or default based on the condition. I've already described how to conditionally add a class to a React style.

const className = props.active ? 'default' : 'active'

The StylesComponent.css file contains the CSS style that we have stored.

.active {
    background: steelblue;
}
.default {
    background: #d1d1d1;
}

We can now manage some extra state in the App component that will store the boolean false and update the value accordingly.

const [active, setActive] = useState('false')

I will now pass this state updating method within the displayForm() function along with the argument active, which will operate in the opposite direction as the state stored value.

const displayForm = () => {
  setAddForm(!addForm)
  setActive(!active)
}

As the last step, we must pass the state variable as a value and the JSX property active to the MyComponent element.

<MyComponent onClick={displayForm} active={active} />

When the button toggles, it will dynamically modify the button's style.

Conclusion

This section showed us how to dynamically apply a classname based on state hook, modify the background color, and show and hide functional components or forms with state updates on button clicks.

React Conditional Rendering with example- part 13

React js tutorial - condition rendering with react ternary and react if return statement


In a previous lesson, we learned how to filter lists by language and filter down lists on the screen, but now I want to render different elements depending on whether a condition is true or not. Data is being fetched from the app component. 

Because there are 13 parts to the react series, all of the code is already written here. If you're interested in how it works, you may start with part one.

If a given language is missing from the array, I want to display a message. To do this, we'll apply the condition: if a value is present in the array, display the filter component; otherwise, display the message.

We will study many conditional operators, such as the -

  • If statement 
  • Element variables
  • Logical conditional operator 
  • Ternary conditional operator.

The process is identical to how javascript functions.

In Lists.js, we render the details of our user list. Here, I want to reveal and hide elements depending on conditions.

Ternary Conditional operator

I will use the ternary operator as my first approach, the shorter and simple method. It contains three operands and is represented by a question mark.

condition ? true : false

This operator can be used directly in JSX by enclosing it in curly braces. If there are no items in the array list, we will return a paragraph that says "there is no detail yet!" If expected data is found in the array, we will return that transformed array element.

{(selectedCourse.length === 0) ? <p>There no detail, yet!</p> : (
   selectedCourse.map((user) => 
   <List key={user.id}
   name={user.name} 
   language={user.language} 
   level={user.level} 
  />
 )
)}


Depending on the situation, either the first or second expression is executed and the component is rendered.

import List from './List'
import ListsFilter from './newUser/ListsFilter'
import { useState } from 'react'

const Lists = ({detail}) => {
  const [filterCourse, setFilterCourse] = useState('JavaScript')

  const filterCourseHandler = (selectedCourse) => {
    setFilterCourse(selectedCourse)
    console.log(selectedCourse)
  }
  const selectedCourse = detail.filter((user) => {
    return user.language === filterCourse
  })
  return (
      <section>
        <ListsFilter selected={filterCourse} onDropdown={filterCourseHandler} />
        {(selectedCourse.length === 0) ? <p>There no detail, yet!</p> : (
          selectedCourse.map((user) => 
            <List key={user.id}
              name={user.name} 
              language={user.language} 
              level={user.level} 
            />
          )
        )}
      </section>
    )
}
export default Lists

Logical && operator

The second approach is to use the AND operator, which is represented by two ampersands && and can also be used inside JSX by embedding with curly braces.

First, allow me to explain how it works. If the condition is met, it will evaluate the desired expression; if the condition is not met, it will not check further and will return false.

We'll offer Lists.js two expressions: the first one checks to see if the array has any items, in which case a message is displayed, and the second one determines whether the array length is larger than 0, in which case a list is displayed.

{(selectedCourse.length === 0) && <p>There is no detail, yet!</p>}

{(selectedCourse.length) > 0 &&
  selectedCourse.map((user) => 
    <List key={user.id}
      name={user.name} 
      language={user.language} 
      level={user.level} 
    />
)}

In the preceding example, both conditions are checked, and only the statement that is met or true is executed.

import List from './List'
import ListsFilter from './newUser/ListsFilter'
import { useState } from 'react'

const Lists = ({detail}) => {
  const [filterCourse, setFilterCourse] = useState('JavaScript')

  const filterCourseHandler = (selectedCourse) => {
    setFilterCourse(selectedCourse)
    console.log(selectedCourse)
  }
  const selectedCourse = detail.filter((user) => {
    return user.language === filterCourse
  })
  return (
      <section>
        <ListsFilter selected={filterCourse} onDropdown={filterCourseHandler} />

        {(selectedCourse.length === 0) && <p>There is no detail, yet!</p>}
        {(selectedCourse.length) > 0 && (
          selectedCourse.map((user) => 
            <List key={user.id}
              name={user.name} 
              language={user.language} 
              level={user.level} 
            />
          )
        )}
      </section>
    )
}
export default Lists

Element variable

This is an alternative method for handling conditions; variables can be used to hold items and helps in conditionally rendering components. It has the advantage of being usable anywhere in the JSX, several times if necessary.

In this method, we can declare a variable in the function component called filterContainer and save the message there.

let filterContainer = <p>There is no detail, yet!</p>

then we'll use this variable in combination with an if statement to implement the conditional section and change the variable's value appropriately. 

In order to determine whether we actually have the items in the array with a length greater than 0 and If the do, we'll override the value of the variable and set the map() method to it.

let filterContainer = <p>There is no detail, yet!</p>

if (selectedCourse.length > 0) {
  filterContainer = selectedCourse.map((user) => 
    <List key={user.id}
      name={user.name} 
      language={user.language} 
      level={user.level} 
    />
  )
}

Then, using curly braces to enclose it, we'll add that variable as an expression in JSX. It can dynamically return an array or a message.

import List from './List'
import ListsFilter from './newUser/ListsFilter'
import { useState } from 'react'

const Lists = ({detail}) => {
  const [filterCourse, setFilterCourse] = useState('JavaScript')

  const filterCourseHandler = (selectedCourse) => {
    setFilterCourse(selectedCourse)
    console.log(selectedCourse)
  }
  const selectedCourse = detail.filter((user) => {
    return user.language === filterCourse
  })
  let filterContainer = <p>There is no detail, yet!</p>
  if (selectedCourse.length > 0) {
    filterContainer = selectedCourse.map((user) => 
      <List key={user.id}
        name={user.name} 
        language={user.language} 
        level={user.level} 
      />
    )
  }
  return (
      <section>
        <ListsFilter selected={filterCourse} onDropdown={filterCourseHandler} />
        {filterContainer}
      </section>
    )
}
export default Lists

If Statement

Now, we will use an if return statement to trigger code based on a condition. This is the simplest way to deal with the condition. 

In vanilla javascript executes an if statement and executes a block of code if the condition returns true,  While React renders a separate component or JSX element entirely according to the supplied condition. 

Also, keep in mind that using an if condition inside JSX, will not work.

In the following example, I'll use if and compare array length to 0 to see if there are any items in the array, and if so, I'll return a  JSX element span. If the condition returns false, I'll return a different JSX code and it'll output lists, no need to use else.

if (props.items.length === 0 ) {
  return There is no detail, yet!
}
return (
  <section>
    {props.items.map((user) => 
      <List key={user.id}
        name={user.name} 
        language={user.language} 
        level={user.level} 
       />
    )} 
 </section>
)

Extract logic in new component

Because only a little section of the JSX that we returned changed, I must extract the filter logic into a new component in order for it to function in my application. There, I will run the condition and re-render the component.

Create a UserFilter.js file in the component folder and then move the map() loop output, which yields a list item, to the file's return statement. Of course, the selectedCourse method no longer exists in the UserFilter component so we'll pass the function through props.

import List from "./List"
const UserLists = (props) => {
  
  if (props.items.length === 0 ) {
    return <span>There is no detail, yet!</span>
  }
  return (
    <section>
      {props.items.map((user) => 
          <List key={user.id}
            name={user.name} 
            language={user.language} 
            level={user.level} 
          />
        )} 
    </section>
  )
}

export default UserLists

Go ahead and import the UserFilter component into the List component at this point along with adding this element in JSX. Now, define the items property on the UserFilter element to replace selectedCourse with props.listItems inside the UserFilter component.

import ListsFilter from './newUser/ListsFilter'
import { useState } from 'react'
import UserLists from './UserLists'

const Lists = ({detail}) => {
  const [filterCourse, setFilterCourse] = useState('JavaScript')

  const filterCourseHandler = (selectedCourse) => {
    setFilterCourse(selectedCourse)
    console.log(selectedCourse)
  }
  const selectedCourse = detail.filter((user) => {
    return user.language === filterCourse
  })
  return (
      <section>
        <ListsFilter selected={filterCourse} onDropdown={filterCourseHandler} />
        <UserLists items={selectedCourse} />
      </section>
    )
}
export default Lists

Conclusion

In this section, we learned how to use condition in React using four different methods and thoroughly examined each of our four options - element variables, the if statement, the ternary operator, and the short circuit (&&) operator. If there is no item return in the array, we render message; however, when there are arrays in the list, we render component.