React Hooks With Typescript: Use State And Use Effect
In this blog, we are going to see how functional components can be used with react hooks to reduce the amount of code used in writing class-based components while still achieving all the features it has.
We are going to use typescript for this tutorial so that our code remains 100% typesafe, and I must say if you are doing a big project, Typescript is a must feature one should go with, which helps to keep the code clean.
npx create-react-app codersera-hooks-tutorial --template typescript
# or
yarn create react-app codersera-hooks-tutorial --template typescript
The above command will create a project with the name codersera-hooks-tutorial. Once it is done, go straight to the directory and either npm start or yarn start will kickstart the project.
We will be using yarn throughout this tutorial to maintain consistency.
Let us now integrate antd ( a design library by the name of ant design), which we will be using to have some standard UI components. And, this does not have to do anything with hooks or react in general.
Integrating antd in react with hooks
- Add antd to dependency
yarn add antd
- Add antd css to load stylings
# src/index.tsx
....
import 'antd/dist/antd.css';
.....
That’s all, we now have a complete typescript setup off react with antd design library integrated.
Using State with hooks in React (React.useState)
Let us see how the state is used with hooks. For this, we are going to create a simple form component, that will show the value in the input field upon submitting the form.
- Create a StateHooksComponent.tsx file inside src/components directory, create the directory if not already there.
- Now create a function StateHooksComponent and import the component in App.tsx file.
#src / components / StateHooksComponent.tsx
import React from "react";
interface Props {}
const StateHooksComponent: React.FC < Props > = ({}) => {
return ( <
div >
State Hooks component <
/div>
)
}
export default StateHooksComponent;
After this, your App.tsx file would look like this:
import React from 'react';
import './App.css';
import StateHooksComponent from './components/StateHooksComponent';
const App: React.FC = () => {
return ( <
div className = "App" >
<
StateHooksComponent / >
<
/div>
);
}
export default App;
Now, let’s add a button, input field, and output view in StateHooksComponents.
const [name, setName] = useState<string>('');
The useState will return 2 things, one is the state variable, and the other is the dispatcher to set this state. We can use any naming convention, but it’s obvious to use the following syntax :
[xxx, setXxx]
The handler is assigned an arrow function. For instance, there are two handlers for handlingSubmit and handling onChangeEvent.
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
const onNameChange = (e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
After making the following edits, your component will look something like this:
import React, {
ChangeEvent,
FormEvent,
useState
} from "react";
import {
Form,
Input,
Button
} from "antd";
interface Props {}
const StateHooksComponent: React.FC < Props > = ({}) => {
const [name, setName] = useState < string > ('');
const handleSubmit = (e: FormEvent < HTMLFormElement > ) => {
e.preventDefault();
console.log(name);
};
const onNameChange = (e: ChangeEvent < HTMLInputElement > ) => {
setName(e.target.value);
};
return ( <
Form layout = "inline"
onSubmit = {
handleSubmit
} >
<
Form.Item >
<
Input type = "text"
placeholder = "name"
value = {
name
}
onChange = {
onNameChange
}
/> <
Button htmlType = "submit"
type = "primary" > Submit < /Button> <
/Form.Item> <
/Form>
)
}
export default StateHooksComponent;
And here is the output that you should expect after typing some content in the box and clicking on submit button.
Using Effects/Lifecycle with Hooks (React.useEffect)
useEffect basically provides the features of componentWillUpdate, componentWillMount, componentWillUnMount all in one.
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component will be unmount')
}
}, []); # notice the empty array here, this is optional
Now, the above code is an example of generic useEffect, notice the empty array above. There are 3 ways in which the useEffect can be used.
- If the array is empty, the function will get executed once during the mounting of the component, and the return function will be executed during unmounting. For example, this can be used to initiate API calls to fetch data that needs to be shown on the UI.
- If no array is provided, the function will be executed before and after each render, this is used to record how many times rendering is taking place.
- If there is any state variable inside the array, then the effects function is executed once on the mounting of the component, and then each time the state is changed, the function is called. A very useful example of this property is, suppose you want to show an autosuggest option, let’s say a user is typing in an input field and based on the initial text you want to show him auto-suggested words/sentence, then you can use this property to fetch the data from backend each time the input value is changing.
.......
const [name, setName] = useState<string>('');
const [options, setOptions] = useState<Array<string>>([]);
useEffect(()=> {
if(name){
// fetch auto suggest options from backend,
setOptions(data);
}
}, [name])
..........
Now each time user types any character in the input field, which is assigned to a name, auto-suggest data will be fetched from the server and updated to the options state, which can be used to show the auto-suggest options
Below is the code block to show how the use effect will be called :
import React, {
ChangeEvent,
FormEvent,
useState,
useEffect
} from "react";
import {
Form,
Input,
Button
} from "antd";
interface Props {}
const StateHooksComponent: React.FC < Props > = ({}) => {
const [name, setName] = useState < string > ('');
const [address, setAddress] = useState < string > ('');
const handleSubmit = (e: FormEvent < HTMLFormElement > ) => {
e.preventDefault();
console.log(name);
};
const onNameChange = (e: ChangeEvent < HTMLInputElement > ) => {
setName(e.target.value);
};
const onAddressChange = (e: ChangeEvent < HTMLInputElement > ) => {
setAddress(e.target.value);
};
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component will be unmount');
}
}, []);
useEffect(() => {
console.log(`Any state changed Name: ${name}, Address: ${address}`);
});
useEffect(() => {
console.log(`Name changed: ${name}`);
}, [name]);
return ( <
Form layout = "inline"
onSubmit = {
handleSubmit
} >
<
Form.Item >
<
Input type = "text"
placeholder = "name"
value = {
name
}
onChange = {
onNameChange
}
/> <
Input type = "text"
placeholder = "address"
value = {
address
}
onChange = {
onAddressChange
}
/> <
Button htmlType = "submit"
type = "primary" > Submit < /Button> <
/Form.Item> <
/Form>
)
};
export default StateHooksComponent;
NOTE: Never change the state of the variable in 2, and never change the state of the variable you are watching in case 3 inside the effect function, otherwise use effects will create an endless loop.
The above code will produce the following output:
So, this is how you can use functional components instead of class-based components and still use all the features that you were able to do with the class lifecycle methods.
FAQ
Q1. Should I use TypeScript with React hooks?
Ans- Evidently, using TypeScript with React hooks is easier than using it with React classes. And because strong typing is valuable security for code safety, you should consider using TypeScript if your new project uses hooks. You should definitely use hooks if you want some TypeScript.
Q2. Is React good with TypeScript?
Ans- Using TypeScript with React provides better IntelliSense, and code completion for JSX.
Q3. What is TypeScript useEffect?
Ans- useEffect with TypeScript
The useEffect is how we manage side effects such as API calls and also utilize the React lifecycle in function components. useEffect takes a callback function as its argument, and the callback can return a clean-up function.