React new use hook
New hook Introduce in React Experimental Version Use() hook.
Introduction
React Teams Introduce a new hook which will change the way of writing react hook in future. There are couple of frameworks are newly came namely Qwick, Solid, svelte and giving a tough challenge to ReactJS and in their ecosystem in terms of scalability, performance, readability, maintainability. So React community coming up with new ideas from other frameworks and where they wanted to solve complex problems in simple way. The React new experimental hook use() is one of the best example of it.
use hooks designed to provide much the same programming model as async/await, while still working inside regular (non-async) function components and Hooks. Similar to async functions in JavaScript, the runtime for use maintains an internal state machine to suspend and resume; but from the perspective of the component author, it looks and feels like a sequential function.
React Hook Limitation and Use Hook Advantage
Use hook come in React experimental version, but before using it we need to understand that why we need it, Can we not solve the problem which we wanted to achive by using useEffect hook and the answer is yes we can solve it by using useEffect hook but there is some limitation.
await is not supported inside components that run on the client, due to technical limitations that will be explained in a later section. Instead, React provides a special Hook called use. You can think of use as a React-only version of await. Just as await can only be used inside async functions, use can only be used inside React components and Hooks.
So it means that you can only use await inside the useEffect hook with async function, You cannot directly call the async/await inside the component you need to wrap it in useEffect hook and not only that you cannot call any react hook inside if/else block or any block statement. So now react solves this problems by using use hook which can be used as First class support which means the code that you are creating to write use hook can be used as a variable on the root level of your application. Also you can wrap use hook inside any block statement like if/else block. To understand in a simple way lets jump into the code and see how it will make your coding life easy.
Create Project using Vite
We will create a React Typescript Project (react-experimental) using Vite, as it is one of the based frontend tooling. So we will use Vite to create React Typescript Project.
yarn create vite react-experimental --template react-ts
Add/Install React Experimental Version
Now we need to install the react experimental version in our Vite project in order to get the latest use hook.\
yarn add react@experimental react-dom@experimental
Add Experimental Type in tsConfig File
In order to use use hook from react js in typescript project we need to define the react/experimental type in tsconfig.json file in the types array, as it is automatically added we need to add it manually otherwise it cannot find the use hook from react module.
// tsconfig.json
"compilerOptions": {
// ... other configs
"types": ["react/experimental"]
}
How We Fetch data in Nowadays Without Using use() hook
Inside the src/App.tsx we will write below this code to fetch data using useEffect hook.
// src/App.tsx
import './App.css';
import Page from './Page';
function App() {
return (
<>
<Page />
</>
)
}
export default App
// src/models/Product.ts
export interface Product = {
id: number,
title: string,
brand: string,
description: string,
category: string,
price: number,
rating: number,
discountPercentage: number,
stock: number,
thumbnail: string,
images: string[]
}
// src/Page.tsx
import { useEffect, useState } from "react";
import { Product } from './models/Product.ts';
function Page() {
const [product, setProduct] = useState<Product>();
useEffect(()=>{
fetch('https://dummyjson.com/products/2')
.then(res => res.json())
.then(json => setProduct(json))
},[])
if(!product) return <div>Loading...</div>
return (
<div>{product.title}</div>
)
}
export default Page
So in here you can see that we are calling the api in the useEffect hook and we cannot use the useEffect hook inside any block statement like if/else block. So now look the api implementation using use hook given below.
// src/Page.tsx
import { use } from 'react';
import { Product } from './models/Product.ts';
const getProduct = fetch('https://dummyjson.com/products/2').then(res => res.json())
const Page = () => {
const product = use<Product>(getProduct)
return (
<>
<div>{product.title}</div>
</>)
};
export default Page;
So now you can see that how easy it is write the api code using use hook, You can use as First Class Component where in the root level you can define your product varibale using use hook and you can also wrap your use hook inside any if statement for example If you want to get the data based on true false value then you can modify your same code in this way.
// src/Page.tsx
import { use } from 'react';
import { Product } from './models/Product.ts';
const getProduct = fetch('https://dummyjson.com/products/2').then(res => res.json())
const Page = ({ isApiData }) => {
let product;
if (isApiData) {
product = use<Product>(getProduct)
}
return (
<>
<div>{product?.title}</div>
</>)
};
export default Page;
// src/App.tsx
import './App.css';
import Page from './Page';
function App() {
return (
<>
<Page isApiData={true} />
</>
)
}
export default App
Now we got the data but if we see the code we got the res.json() response, so it means that we may get the success data or error data and also we need to loader when we will not get the data at the time of api call.
Implement the Loader For API Call using Suspense
So to achieve the loader use hook by default give suspense component from React to use in the parent component of Page component, in here it will be App Component, like in this way.
// src/App.tsx
import { Suspense } from 'react';
import './App.css';
import Page from './Page';
function App() {
return (
<>
<Suspense fallback={<div>Loading</div>}>
<Page isApiData={true} />
</Suspense>
</>
)
}
export default App
Catch the Error For API Call using ErrorBoundary
So if we get any error from the API Call then we can achive the error using ErrorBoundary. So first we need to create the ErrorBoundary and then we will wrap it inside the App component.
// src/ErrorBoundary.tsx
import { Component } from "react";
class ErrorBoundary extends Component {
state = { hasError: false, error: null };
constructor(props: any) {
super(props);
}
static getDerivedStateFromError(error: any) {
return { hasError: true, error };
}
componentDidCatch(error: any, info: any) {
console.error('Error caught:', error, info);
}
render() {
if ((this.state as any).hasError) {
return (this.props as any).fallback
}
return (this.props as any).children;
}
}
export default ErrorBoundary;
So if we have any error then it will be catch in the hasError function and it has fallback props and that we need to pass in the App component to get the fallback content if we get any error.
// src/App.tsx
import { Suspense } from 'react';
import './App.css';
import ErrorBoundary from './ErrorBoundary';
import Page from './Page';
function App() {
return (
<>
<ErrorBoundary fallback={<div>There is Some Error Happen</div>}>
<Suspense fallback={<div>Loading</div>}>
<Page isApiData={true} />
</Suspense>
</ErrorBoundary>
</>
)
}
export default App
So now we think we are all set but the answer is no, For example if we get error at the initial page load then it will call the apis multiple times. So to avoid that thing we can cached our apis and it will drastically improved the performance.
Cache use hook API
We can use hook api by using in memory cache object, code is given below.
import { use } from 'react';
import { Product } from './models/Product.ts';
const cachedFetches: any = {};
const cachedFetch = (url: string) => {
if (!cachedFetches[url]) {
cachedFetches[url] = fetch(url).then(async (res) => (await res.json()));
}
return cachedFetches[url];
};
const Page = ({ isApiData }) => {
let product;
if (isApiData) {
product = use<Product>(cachedFetch('https://dummyjson.com/products/2'))
}
return (
<>
<div>{product?.title}</div>
</>)
};
export default Page;
So we have done the caching of our api using use hook. Now if we need to pass the api data in a nested child component of Page component then we can use context api. But use hook can also used as a context api, it means that instead of useContext we can just use the use hook.
use hook as Context API
We can create a context by using createContext function where we will provide the api data, code is given below.
// src/contexts/Contexts.ts
import { createContext } from 'react';
export default const ProductContext: any = createContext(undefined);
Now we have created the context and now we will pass this context to the page component with the api response.
// src/Page.tsx
import { use } from 'react';
import { Product } from './models/Product.ts';
import ProductContext from './contexts/Contexts'
const cachedFetches: any = {};
const cachedFetch = (url: string) => {
if (!cachedFetches[url]) {
cachedFetches[url] = fetch(url).then(async (res) => (await res.json()));
}
return cachedFetches[url];
};
const Page = ({ isApiData }) => {
let product;
if (isApiData) {
product = use<Product>(cachedFetch('https://dummyjson.com/products/2'))
}
return (
<>
{product &&
<ProductContext.Provider value={product}>
<ChildOne />
</ProductContext.Provider>
</>)
};
export default Page;
So now we can use the context in the ChildOne or any nested component of Page component using use hook.
// src/ChildOne.tsx
import { use } from 'react';
import { Product } from './models/Product.ts';
import ProductContext from './contexts/Contexts'
const ChildOne = () => {
const product = use<Product>(ProductContext);
return (
<>
{product &&
<div>{product.title}</div>
</>)
};
export default ChildOne;
Conclusion
So use hook is not only do one task it can achieve multiple task and it is one of best hook which can solve mutiple problems and make it is easy to write the code and get best output by using use hook. So If you do not try it, just use it in your project and get more productivity.