The useState Hook is used in React to store and update component state. When using TypeScript, we can provide a type for the state so that only valid values can be stored.
useState value automatically. For more complex or
initially empty states, providing an explicit type is useful.
useState is a React Hook that allows a
functional component to store state.
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<h2>{count}</h2>
);
}
Before using useState, import it from React.
import { useState } from "react";
This gives the component access to the
useState Hook.
const [state, setState] = useState(initialValue);
state stores the current value.setState updates the value.initialValue is the starting value.TypeScript can infer the type from the initial value.
const [count, setCount] = useState(0);
TypeScript understands that count is a
number.
We can explicitly specify the state type using a generic.
const [count, setCount] = useState<number>(0);
The state can now contain only numbers.
const [count, setCount] = useState<number>(0);
setCount(10);
The setCount function updates the state.
const [name, setName] = useState<string>("");
setName("Rahul");
The state is restricted to string values.
const [isLoggedIn, setIsLoggedIn] =
useState<boolean>(false);
setIsLoggedIn(true);
Boolean state is useful for values such as login status, loading state, and visibility.
const [names, setNames] =
useState<string[]>([]);
setNames(["Rahul", "Amit", "Priya"]);
The state above can contain an array of strings.
const [marks, setMarks] =
useState<number[]>([]);
setMarks([80, 75, 90]);
Every item in the array must be a number.
interface User {
name: string;
age: number;
}
const [user, setUser] =
useState<User>({
name: "Rahul",
age: 20
});
An interface can describe the structure of an object state.
setUser({
name: "Amit",
age: 22
});
The new object must follow the User interface.
The spread operator can preserve the other properties.
setUser({
...user,
age: 21
});
Only the age property is changed in the new
state object.
A state can accept more than one type using a union type.
const [value, setValue] =
useState<string | number>("");
setValue("Hello");
setValue(100);
Sometimes state starts with null and later
receives an object.
interface User {
name: string;
}
const [user, setUser] =
useState<User | null>(null);
The state can contain either a User object or
null.
if (user) {
console.log(user.name);
}
The condition ensures that user is not null
before accessing its properties.
When an array starts empty, providing a type can clearly describe what it will contain.
const [students, setStudents] =
useState<string[]>([]);
setStudents([
...students,
"Rahul"
]);
The spread operator creates a new array containing the existing students and the new student.
setStudents(
students.filter(
student => student !== "Rahul"
)
);
filter() can create a new array without the
selected item.
When the next state depends on the previous state, use the functional update form.
setCount(previousCount =>
previousCount + 1
);
This is useful when updating state based on its previous value.
const [name, setName] =
useState<string>("");
const [age, setAge] =
useState<number>(0);
const [active, setActive] =
useState<boolean>(false);
A component can have multiple state variables.
const [name, setName] =
useState<string>("");
return (
<input
value={name}
onChange={(event) =>
setName(event.target.value)
}
/>
);
The state can store the current value of an input field.
import { useState } from "react";
function Counter() {
const [count, setCount] =
useState<number>(0);
return (
<div>
<h2>Count: {count}</h2>
<button
onClick={() =>
setCount(
previousCount =>
previousCount + 1
)
}
>
Increase
</button>
</div>
);
}
const [loading, setLoading] =
useState<boolean>(false);
setLoading(true);
// perform operation
setLoading(false);
Boolean state is commonly used to represent loading status.
interface Product {
id: number;
name: string;
price: number;
}
const [products, setProducts] =
useState<Product[]>([]);
This pattern is useful when storing typed API data in React state.
null when the state can be null.TypeScript inference is often enough for simple state.
const [count, setCount] = useState(0);
An explicit type is especially useful when the initial value does not fully describe the future state.
const [user, setUser] =
useState<User | null>(null);
The same TypeScript patterns can be used with React Native.
import { useState } from "react";
import { Text, Button, View } from "react-native";
function Counter() {
const [count, setCount] =
useState<number>(0);
return (
<View>
<Text>
Count: {count}
</Text>
<Button
title="Increase"
onPress={() =>
setCount(
previousCount =>
previousCount + 1
)
}
/>
</View>
);
}
import { useState } from "react";
interface Student {
id: number;
name: string;
course: string;
}
function StudentApp() {
const [student, setStudent] =
useState<Student | null>(null);
const [students, setStudents] =
useState<Student[]>([]);
const [loading, setLoading] =
useState<boolean>(false);
const addStudent = () => {
const newStudent: Student = {
id: 101,
name: "Rahul",
course: "React Native"
};
setStudent(newStudent);
setStudents(previousStudents => [
...previousStudents,
newStudent
]);
};
return (
<div>
<h2>Student Management</h2>
<button
onClick={addStudent}
disabled={loading}
>
Add Student
</button>
{student && (
<div>
<p>
ID: {student.id}
</p>
<p>
Name: {student.name}
</p>
<p>
Course: {student.course}
</p>
</div>
)}
<p>
Total Students: {students.length}
</p>
</div>
);
}
export default StudentApp;
This example combines object state, nullable state, array state, boolean state, interfaces, and functional state updates.
useState is used to manage component state.useState<type>() when an explicit type is useful.User | null for nullable state.Question: Which syntax explicitly tells TypeScript that a useState value is a number?