React Hooks are a recent addition to React that allows developers to add state and other React features to functional components. Typescript, a statically typed superset of JavaScript, adds more power and reliability to the development process by providing type checking during compile time.
In this blog post, we’ll go over some common React Hooks and explore how they can be used with Typescript.
useState Hook
The useState Hook is used to add state to functional components. It returns an array containing the current state value and a function to update the state. The type of the state value can be inferred from the initial value passed to useState or explicitly declared using Typescript.
Suppose you have a simple form with two input fields, a name and an email. You can use the useState Hook to manage the state of the input fields, and update them as the user types.
import React, { useState } from "react";
const Form: React.FC = () => {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
setName(event.target.value);
};
const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
setEmail(event.target.value);
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
event.preventDefault();
console.log(`Name: ${name}, Email: ${email}`);
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input type="text" id="name" value={name} onChange={handleNameChange} />
<label htmlFor="email">Email:</label>
<input type="email" id="email" value={email} onChange={handleEmailChange} />
<button type="submit">Submit</button>
</form>
);
};
export default Form;
In the example above, the useState Hook is used to handle the state of the name and email input fields, and we assign an initial empty string value to each state variable.
Two functions are created to update the state variables based on user input in the input fields, which are then integrated into the onChange handlers of the input elements.
Finally, the handleSubmit function is implemented to print the current values of the name and email state variables when the form is submitted.
By using the useState Hook, we are able to manage and update the simple state in our components as the user interacts with it.
useEffect Hook
The useEffect Hook is used to handle side effects in functional components. It’s similar to the componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle methods in class components. The useEffect Hook takes two arguments: a function that contains the side effect logic and an array of dependencies.
import React, { useState, useEffect } from "react";
const Timer: React.FC = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setSeconds((prevSeconds) => prevSeconds + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
return (
<div>
<h1>Timer: {seconds}s</h1>
</div>
);
};
export default Timer;
In this example, the useEffect Hook is used to create a timer that updates the number of seconds displayed in the component every second.
The useEffect Hook requires two arguments: a function to execute after the component has rendered, and an optional array of dependencies.
The first argument is an anonymous function that sets up a timer using the setInterval function, and updates the seconds state variable every second using the setSeconds function.
The second argument is an empty array, indicating that this effect should only be executed once when the component mounts and not again unless the component is unmounted and mounted again.
In addition, the useEffect Hook provides a cleanup function that clears the interval to prevent memory leaks when the component is unmounted.
Lastly, the current value of the seconds state variable is displayed in the component.
Using the useEffect Hook allows for performing actions after rendering, such as setting up timers, fetching data, or subscribing to events.
useContext Hook
The useContext Hook is used to access data from the React context in functional components. It takes a context object created by the React.createContext method and returns the current context value.
Suppose you have a theme that you want to apply to your entire application. You can create a ThemeContext using the createContext method and provide it with a default theme. Then, you can use the useContext Hook to access the current theme value in your components.
import React, { useContext } from "react";
interface Theme {
backgroundColor: string;
color: string;
}
const defaultTheme: Theme = {
backgroundColor: "white",
color: "black"
};
const ThemeContext = React.createContext(defaultTheme);
const App: React.FC = () => {
return (
<ThemeContext.Provider value={defaultTheme}>
<div>
<Header />
<Main />
<Footer />
</div>
</ThemeContext.Provider>
);
};
const Header: React.FC = () => {
const theme = useContext(ThemeContext);
return (
<header style=>
<h1>My App</h1>
</header>
);
};
const Main: React.FC = () => {
const theme = useContext(ThemeContext);
return (
<main style=>
<p>Welcome to my app!</p>
</main>
);
};
const Footer: React.FC = () => {
const theme = useContext(ThemeContext);
return (
<footer style=>
<p>Copyright © 2023</p>
</footer>
);
};
export default App;
In the above example, a ThemeContext is established using the createContext function with a default theme provided. The useContext Hook is then utilized in the Header, Main, and Footer components to retrieve the current theme value. By doing so, the same theme can be applied to all components without the need to pass it down via props.
useReducer Hook
The useReducer Hook is used to manage state in more complex components. It takes a reducer function and an initial state value as arguments and returns an array containing the current state value and a dispatch function to update the state.
Suppose you have a simple counter that you want to increment or decrement by clicking buttons. You can use the useReducer Hook to manage the state of the counter, and handle different actions like incrementing or decrementing the counter value.
import React, { useReducer } from "react";
interface CounterState {
count: number;
}
interface CounterAction {
type: string;
payload?: any;
}
const initialState: CounterState = {
count: 0
};
const reducer = (state: CounterState, action: CounterAction): CounterState => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
case "RESET":
return initialState;
default:
return state;
}
};
const Counter: React.FC = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const handleIncrement = (): void => {
dispatch({ type: "INCREMENT" });
};
const handleDecrement = (): void => {
dispatch({ type: "DECREMENT" });
};
const handleReset = (): void => {
dispatch({ type: "RESET" });
};
return (
<div>
<h2>Count: {state.count}</h2>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
<button onClick={handleReset}>Reset</button>
</div>
);
};
export default Counter;
In the example shown above, a reducer function is created to handle various actions such as incrementing, decrementing, or resetting the counter value. To manage the counter state, the useReducer Hook is used along with the reducer function and the initial state.
Three functions are also created that dispatch different actions to the reducer function, which are then used in the onClick handlers of three buttons. Finally, the current count value is displayed using the state variable returned by useReducer.
This approach enables managing more complex state in components using the useReducer Hook and handling different actions in a type-safe manner.
Conclusion
React Hooks offer an intuitive and powerful way to incorporate state and other React features into functional components. When paired with Typescript, they provide even greater reliability and type safety to the development process.
This blog post has explored several common React Hooks and demonstrated how they can be used effectively with Typescript. We have demonstrated how the useState Hook can be utilized to add state to a component, how the useEffect Hook can be utilized to manage side effects, how the useContext Hook can be utilized to access data from the context, and how the useReducer Hook can be utilized to handle more complex state. By utilizing these tools, developers can create more efficient, reliable, and type-safe React applications.
If you liked this article, you can buy me a coffee
Leave a comment