Our Global Presence

Canada
57 Sherway St,
Stoney Creek, ON
L8J 0J3

India
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049

USA
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
In this post, we will cover five simple React hooks that you will find handy in any project. These hooks are useful no matter the features of the application. For each hook, we will provide the implementation and the client code sample.
Web applications use modals extensively and for various reasons. When working with modals, you quickly realize that managing their state is a tedious and repetitive task. And when you have code that’s repetitive and tedious, you should take time to abstract it. That’s what useModalState
does for managing modal states.
Many libraries provide their version of this hook, and one such library is Chakra UI. If you want to learn more about Chakra UI, check out my blog post here.
The implementation of the hook is very simple, even trivial. But in my experience, it pays off using it rather than rewriting the code for managing the modal’s state each time.
import React from "react"; import Modal from "./Modal"; export const useModalState = ({ initialOpen = false } = {}) => { const [isOpen, setIsOpen] = useState(initialOpen); const onOpen = () => { setIsOpen(true); }; const onClose = () => { setIsOpen(false); }; const onToggle = () => { setIsOpen(!isOpen); }; return { onOpen, onClose, isOpen, onToggle }; };
And here’s an example of client code using the hook:
const Client = () => { const { isOpen, onToggle } = useModalState(); const handleClick = () => { onToggle(); }; return ( <div> <button onClick={handleClick} /> <Modal open={isOpen} /> </div> ); }; export default Client;
useConfirmationDialog
is another modal-related hook that we use quite often. It’s a common practice to ask users for confirmations when performing sensitive actions, like deleting records. So it makes sense to abstract that logic with a hook. Here’s a sample implementation of the useConfirmationDialog
hook:
import React, { useCallback, useState } from 'react'; import ConfirmationDialog from 'components/global/ConfirmationDialog'; export default function useConfirmationDialog({ headerText, bodyText, confirmationButtonText, onConfirmClick, }) { const [isOpen, setIsOpen] = useState(false); const onOpen = () => { setIsOpen(true); }; const Dialog = useCallback( () => ( <ConfirmationDialog headerText={headerText} bodyText={bodyText} isOpen={isOpen} onConfirmClick={onConfirmClick} onCancelClick={() => setIsOpen(false)} confirmationButtonText={confirmationButtonText} /> ), [isOpen] ); return { Dialog, onOpen, }; }
And here’s an example of the client code:
import React from "react"; import { useConfirmationDialog } from './useConfirmationDialog' function Client() { const { Dialog, onOpen } = useConfirmationDialog({ headerText: "Delete this record?", bodyText: "Are you sure you want delete this record? This cannot be undone.", confirmationButtonText: "Delete", onConfirmClick: handleDeleteConfirm, }); function handleDeleteConfirm() { //TODO: delete } const handleDeleteClick = () => { onOpen(); }; return ( <div> <Dialog /> <button onClick={handleDeleteClick} /> </div> ); } export default Client;
One thing to note here is that this implementation works fine as long as your confirmation modal doesn’t have any controlled input elements. If you do have controlled inputs, it’s best to create a separate component for your modal. That’s because you don’t want the content of the modal, including those inputs, to re-render each time the user types something.
Properly handling async actions in your application is trickier than it seems at first. There are multiple state variables that you need to keep track of while the task is running. You want to keep the user informed that the action is processing by displaying a spinner. Also, you need to handle the errors and provide useful feedback when they happen. So it pays off to have an established framework for dealing with async tasks in your React project. And that’s where you might find useAsync
useful. Here’s an implementation of the useAsync
hook:
export const useAsync = ({ asyncFunction }) => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [result, setResult] = useState(null); const execute = useCallback( async (...params) => { try { setLoading(true); const response = await asyncFunction(...params); setResult(response); } catch (e) { setError(e); } setLoading(false); }, [asyncFunction] ); return { error, result, loading, execute }; };
The client code:
import React from "react"; export default function Client() { const { loading, result, error, execute } = useAsync({ asyncFunction: someAsyncTask, }); async function someAsyncTask() { // perform async task } const handleClick = () => { execute(); }; return ( <div> {loading && <p>loading</p>} {!loading && result && <p>{result}</p>} {!loading && error?.message && <p>{error?.message}</p>} <button onClick={handleClick} /> </div> ); }
The hook is not hard to write yourself and that’s what we often do. But it might make sense for you to use a more mature library implementation instead. Here’s a great option.
Form validation is another part of React applications that people often find tedious. With that said, there are plenty of great libraries to help with forms management in React. One great alternative is formik. However, each of those libraries has a learning curve. And that learning curve often makes it not worth using in smaller projects. Particularly if you have others working with you and they are not familiar with those libraries.
But it doesn’t mean we can’t have simple abstractions for some of the code we often use. One such piece of code that we like to abstract is error validation. Checking forms before submitting to API and displaying validation results to the user is a must-have for any web application. Here’s an implementation of a simple useTrackErrors
hook that can help with that:
import React, { useState } from "react"; import FormControl from "./FormControl"; import Input from "./Input"; import onSignup from "./SignupAPI"; export const useTrackErrors = () => { const [errors, setErrors] = useState({}); const setErrors = (errsArray) => { const newErrors = { ...errors }; errsArray.forEach(({ key, value }) => { newErrors[key] = value; }); setErrors(newErrors); }; const clearErrors = () => { setErrors({}); }; return { errors, setErrors, clearErrors }; };
And here’s the client implementation:
import React, { useState } from "react"; import FormControl from "./FormControl"; import Input from "./Input"; import onSignup from "./SignupAPI"; export default function Client() { const { errors, setErrors, clearErrors } = useTrackErrors(); const [name, setName] = useState(""); const [email, setEmail] = useState(""); const handleSignupClick = () => { let invalid = false; const errs = []; if (!name) { errs.push({ key: "name", value: true }); invalid = true; } if (!email) { errs.push({ key: "email", value: true }); invalid = true; } if (invalid) { setErrors(errs); return; } onSignup(name, email); clearErrors(); }; const handleNameChange = (e) => { setName(e.target.value); setErrors([{ key: "name", value: false }]); }; const handleEmailChange = (e) => { setEmail(e.target.value); setErrors([{ key: "email", value: false }]); }; return ( <div> <FormControl isInvalid={errors["name"]}> <FormLabel>Full Name</FormLabel> <Input onKeyDown={handleKeyDown} onChange={handleNameChange} value={name} placeholder="Your name..." /> </FormControl> <FormControl isInvalid={errors["email"]}> <FormLabel>Email</FormLabel> <Input onKeyDown={handleKeyDown} onChange={handleEmailChange} value={email} placeholder="Your email..." /> </FormControl> <button onClick={handleSignupClick}>Sign Up</button> </div> ); }
Debouncing has a broad use in any application. The most common use is throttling expensive operations. For example, preventing the application from calling the search API every time the user presses a key and letting the user finish before calling it. The useDebounce
hook makes throttling such expensive operations easy. Here’s a simple implementation that’s written using AwesomeDebounceLibrary under the hood:
import AwesomeDebouncePromise from "awesome-debounce-promise"; const debounceAction = (actionFunc, delay) => AwesomeDebouncePromise(actionFunc, delay); function useDebounce(func, delay) { const debouncedFunction = useMemo(() => debounceAction(func, delay), [ delay, func, ]); return debouncedFunction; }
And here’s the client code:
import React from "react"; const callAPI = async (value) => { // expensice API call }; export default function Client() { const debouncedAPICall = useDebounce(callAPI, 500); const handleInputChange = async (e) => { debouncedAPICall(e.target.value); }; return ( <form> <input type="text" onChange={handleInputChange} /> </form> ); }
One thing to note with this implementation: You need to ensure that the expensive function is not recreated on each render. Because that will reset the debounced version of that function and wipe out its inner state. There are two ways to achieve that:
And that’s it for this post. There are many useful hook libraries worth checking out, and if you’re interested, here’s a great place to start. While there are many helpful custom hooks out there, these five are the ones that you will find handy in any React project.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone while being compatible with the newest features of React.
While working with react you might have noticed that are different ways to manage the global state management in React. Let’s take look at the options that we have:
Redux is a predictable state container for JavaScript apps.
It is used by a lot of web apps these days, it allows us to have a global state, register components to it and they will re-render by themselves every time a value they registered to will change.
Context API is another approach that devs take for better management of state within the application.
Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
Now that we are already using to above two famous ways of adding global state to our application here comes something new i.e Recoil.
Recoil lets you create a data-flow graph that flows from atoms (shared state) through selectors (pure functions) and down into your React components.
React
local component state. If the same atom is used from multiple components, all those components share their state.Let’s try to understand this with a Demo example.
Consider we want to store user data upon login into our application and share between two components,
Let first define an atom which stores the logged-in user Data
pic courtesy: blog.bitsrc.io
In the above example, we have stored the object which has a name in it. It is stored inside our loggedInUserData
atom.
Now consider we need to show this name in our useRecoilState
.
pic courtesy: blog.bitsrc.io
And our component looks something like this, which display the data from the same atom which is used in the header component again with help of useRecoilState
pic courtesy: blog.bitsrc.io
The syntax might look quite similar to useState which we are already used to in react
hooks.
As in the above example since the same state is shared between the
This is one of the important hooks in the Recoil API. This hook will just subscribe to the component to the given Recoil state, it is used to return the value of the given Recoil state.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
Hooks are quite possibly the most eagerly awaited addition to React since the rewrite. Does the product live up to the hype? From my perspective, yes, as they really are a great feature. They are essentially functions that open up new opportunities, such as:
There are few React hooks that are included as default. The three basic ones are useState, useEffect, and useContext. There are also several additional ones, e.g., useRef and useMemo, but for now, we shall focus on the basics.
Let’s take a look at useState, and let’s use it to create an example of a straightforward counter. How does it work? Well, basically, the whole construct is really straightforward and looks like:
export function Counter() { const [counter, setCounter] = React.useState(0); return ( <div> {counter} <button onClick={() => setCounter(counter + 1)}>+</button> </div> ); };
It is invoked with initialState (value) and returns an array with two elements with it. Thanks to array destructuring assignment, we can assign the variables to these elements right away. The first one is always the last state after updates, while the other one is a function that we will use to update the value. Seems rather easy, doesn’t it?
Also, due to the fact that such components used to be called stateless functional components, such a name is not appropriate anymore, because they can have a state as it is shown above. Hence, the names class components and function components seem to be more in line with what they actually do, at least from 16.8.0.
The update function (in our case setCounter), can also be used as a function which will take the previous value as an argument in the following form:
<button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button> <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>
However, unlike the this.setState class component which was doing a shallow merge, setting the function (setCounter in our case) is overriding the whole state instead.
In addition, initialState can also be a function, not just a plain value. This has its own benefits, as that function will be run only during the initial render of the component and after that, it won’t be invoked anymore.
const [counter, setCounter] = useState(() => calculateComplexInitialValue());
Finally, if we are going to use setCounter with the exact same value that we had at the very same moment in the current state (counter), then component will not rerender.
On the other hand, useEffect is about adding side effects to our functional component, be it subscriptions, API calls, timers, or just about anything that we may find useful. Any function that we will pass to useEffect will be run after render, and it will be doing so after every render unless we add a limitation concerning what properties’ changes should be rerun as a second argument of the function. If we want to run it only on mount and clean up on unmount, then we just need to pass an empty array in it.
const fetchApi = async () => { const value = await fetch("https://jsonplaceholder.typicode.com/todos/1"); console.log(await value.json()); }; export function Counter() { const [counter, setCounter] = useState(0); useEffect(() => { fetchApi(); }, []); return ( <div> {counter} <button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button> <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button> </div> ); };
The above code will be only run once due to an empty array as a second argument. Basically, it is something like componentDidMount in such case, but it fires a bit later. If you want to have a similar hook that is called before browser paint, use useLayoutEffect, but these updates will be applied synchronously, unlike useEffect.
useContext seems to be the easiest to understand, as one provides to which context we want to get access (an object that was returned by the createContext function) and in return, it provides us with the value for that context.
const context = useContext(Context);
Finally, to write your own hook, you can just write something like the following:
function useWindowWidth() { let [windowWidth, setWindowWidth] = useState(window.innerWidth); function handleResize() { setWindowWidth(window.innerWidth); } useEffect(() => { window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return windowWidth; }
Basically, we are using the regular useState hook for which we are assigning as initial value window width. Then in useEffect, we are adding a listener which will trigger handleResize on each window resize. We also clear after component will be unmounted (look at the return in useEffect). Easy?
Note: The word used in all hooks is important. It’s used because it allows React to check if you are not doing something bad, e.g., call hooks from regular JS functions.
React had its own props checking, before Flow and TypeScript were an option.
PropTypes checks if the properties (props) that are received by a React component and checks if they’re in line with what we have. Whenever a different situation occurs (e.g., object instead of an array), we will get a warning in the console. It is important to note that PropTypes are only checked in development mode due to their impact on performance and the aforementioned console warning.
As of React 15.5, PropTypes are in a different package that needs to be installed separately. They are declared along properties in a static property called propTypes (surprise), combining them with defaultProps which are used if the properties are undefined (undefined is the only case). DefaultProps are not related to PropTypes, but they can solve some warnings that might appear due to PropTypes.
The other two options are Flow and TypeScript, and they are way more popular nowadays (especially TypeScript).
Personally, I find TypeScript faster (practically instantaneous), especially in autocomplete, which seems a bit slower with Flow. It’s worth noting that IDEs such as WebStorm, which I personally use, employ a CLI for integration with Flow. However, it seems even easier to integrate optional use in files, where you simply add // @flow at the beginning of the file to start type checking. Also, from what I can tell, it seems that TypeScript won the battle versus Flow in the end—it is way more popular now, and some of the most popular libraries are getting refactored from Flow to TypeScript.
There are a few more options, mentioned also in official documentation, such as Reason (developed by Facebook and gaining popularity in the React community), Kotlin (a language developed by JetBrains) and more.
Obviously, for front-end developers, the easiest approach would be to hop in and start using Flow and TypeScript, rather than switch to Kotlin or F#. However, for back-end developers that are transitioning to front-end, these might actually be easier to get started with.
The most basic and obvious change that you need to do for production mode is to switch to “production” for DefinePlugin and add UglifyJsPlugin in the case of Webpack. In the case of CRA, it is as simple as using npm run build (which will be running react-scripts build). Be aware that Webpack and CRA are not the only options, as you can use other build tools like Brunch. This is usually covered in official documentation, be it official React documentation or documentation for a specific tool. To make sure that the mode is set correctly, you can use React Developer Tools, which will give you an indication of what kind of build you are using (production vs. development). The aforementioned steps will make your application run without checks and warnings that come from React and the bundle itself will be minimized, too.
There are a few more things you can do for your React app. What do you do with the JS file that is built? You can start with just “bundle.js” if the size is relatively small, or maybe do something like “vendor + bundle” or maybe “vendor + smallest required part + import things when they are needed.” This is useful when you are dealing with a very big app and you do not need to import everything at the very beginning. Be aware that bundling some JavaScript code in the main bundle that is not even being used will simply increase the bundle size and make the app load slower at the very beginning.
Vendor bundles can be useful if you are planning on freezing libraries’ versions upon realizing they might not change for a long time (if ever). Also, bigger files are better at gzipping so the benefit that you get from separating might sometimes not be worth it. It depends on the file size and sometimes you will simply need to try it yourself.
Code splitting can appear in more ways than suggested here, but let’s focus on what we have available in CRA and React itself. Basically, in order to split code into different chunks, we can use import() which works thanks to Webpack (import itself is a proposal in Stage 3 as of now, so it is not part of the language standard just yet). Whenever Webpack sees import, it will know that it needs to start code splitting at this stage and cannot include it in the main bundle (the code that it is inside the import).
Now we can connect it with React.lazy() which requires import() with a file path containing the component that needs to be rendered in that place. Next, we can use React.suspense() which will display a different component in that place until the imported component is loaded. One might wonder; if we are importing a single component, then why we would need it?
That’s not quite the case, as React.lazy() will be showing the component we import(), but import() might fetch a bigger chunk than that single component. For example, that particular component might have other libraries in tow, more code, etc., so one file isn’t necessary—it might be many more files bundled together. Finally, we can wrap all of that in ErrorBoundary (you can find the code in our section on error boundaries) which will serve as a fallback if something fails with the component we wanted to import (e.g., if there’s a network error).
import ErrorBoundary from './ErrorBoundary'; const ComponentOne = React.lazy(() => import('./ComponentOne')); function MyComponent() { return ( <ErrorBoundary> <React.Suspense fallback={ <div>Loading...</div> }> <ComponentOne/> </React.Suspense> </ErrorBoundary> ); }
This is a basic example, but you can obviously do more. You can use import and React.lazy for dynamic route splitting (e.g., admin vs. regular user, or just really big paths that bring a lot). Be aware that React. lazy only supports default exports as of now and doesn’t support server-side rendering.
Regarding performance, if your React application is acting laggy, there are two tools that can help you figure out the issue.
The first one is Chrome Performance Tab, which will tell you what happens with each component (e.g., mount, update). Thanks to that, you should be able to identify which component is exhibiting performance issues trouble and then optimize it.
The other option is to use DevTools Profiler which became available in React 16.5+, and with cooperation from shouldComponentUpdate (or PureComponent, which was explained in part one of this tutorial), we can improve performance for some critical components.
Obviously, employing basic best practices for the web is optimal, such as debouncing some events (e.g., scroll), being cautious with animations (using transform instead of changing the height and animating it) and so on. Using best practices can be overlooked very easily, especially if you are just getting to grips with React.
For more Information and to build a website using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft“.
To develop your custom website using React JS, please visit our technology page.
Content Source:
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
© 2025 — HK Infosoft. All Rights Reserved.
© 2025 — HK Infosoft. All Rights Reserved.
T&C | Privacy Policy | Sitemap