
Build 10x products in minutes by chatting with AI - beyond just a prototype.
Topics
What is a generic component?
How do you use generic with React component?
Is React getting rid of class components?
When to use FC in React?
Want to make your React components more flexible without losing type safety?
Generic components can help! They let you build reusable elements that work with different data types while keeping TypeScript’s strict checks in place.
This blog breaks down React generic components with simple examples. You’ll learn how to use generic type parameters, work with various data structures, and apply them in real projects.
Let’s get started!
Generics allow React components to be more flexible while maintaining type safety. Instead of defining a fixed data type, generics enable components to work with different data types. This is achieved using generic type parameters that can be defined when using the component.
• Maintaining Type Safety: Ensures that the props and returned data match expected types.
• Code Reusability: Enables the same component to handle multiple data types.
• Better Type Checking: TypeScript ensures that data passed to the component conforms to its generic type.
• Improved Developer Experience: Reduces type errors and increases predictability.
A generic component can be defined using TypeScript generics. The type parameter <T> acts as a placeholder for the data type, making the component work with multiple data structures.
The following example shows a React functional component that renders a list of items using a generic type parameter:
import React from "react"; interface ListProps<T> { items: T[]; renderItem: (item: T) => JSX.Element; } const ListComponent = <T,>({ items, renderItem }: ListProps<T>) => { return ( <ul> {items.map((item, index) => ( <li key={index}>{renderItem(item)}</li> ))} </ul> ); }; // Usage with strings const StringList = () => { const items = ["Apple", "Banana", "Cherry"]; return <ListComponent items={items} renderItem={(item) => <span>{item}</span>} />; }; // Usage with objects const ObjectList = () => { const items = [{ id: 1, name: "John" }, { id: 2, name: "Jane" }]; return <ListComponent items={items} renderItem={(item) => <span>{item.name}</span>} />; }; export default ObjectList;
• The generic type parameter <T> allows the component to handle different data types.
• The ListProps<T> interface ensures type safety.
• The usage examples demonstrate how TypeScript ensures correct data types.
A React component often requires props to be strongly typed. Using TypeScript generics, we can define a generic component that accepts props of any generic type.
The following example creates a generic component that displays a data card:
• Reusability: Works with different data structures.
• Type Safety: Prevents invalid data types.
• Clear Type Checking: TypeScript ensures correct props.
A generic component can be designed to handle different data structures, including arrays, objects, and primitive data types.
This example creates a reusable component for displaying a table.
• TableProps accepts a generic type for handling different data structures.
• The component ensures type safety using TypeScript generics.
• Works with various data types, including string, number, and objects.
A generic function within a React component ensures maintaining type safety when handling various data types.
• Maintains type safety when working with generic types.
• Can handle different data structures.
• The arrow function transformFn allows flexible transformations.
Generics work in React Native the same way they do in React. A React Native generic component can ensure type safety while handling different data types.
React generic components help developers create flexible and reusable code. They work well with TypeScript to manage different data types while keeping everything structured.
Using generics in React makes it easier to build scalable applications. It improves type-checking and reduces errors. With this approach, developers can write cleaner and more maintainable code.
interface CardProps<T> {
data: T;
renderContent: (data: T) => JSX.Element;
}
const Card = <T,>({ data, renderContent }: CardProps<T>) => {
return <div className="card">{renderContent(data)}</div>;
};
// Usage with user objects
const UserCard = () => {
const user = { id: 1, name: "Alice", age: 25 };
return <Card data={user} renderContent={(data) => <p>{data.name} - {data.age}</p>} />;
};
export default UserCard;interface TableProps<T> {
data: T[];
columns: (keyof T)[];
}
const Table = <T,>({ data, columns }: TableProps<T>) => {
return (
<table>
<thead>
<tr>
{columns.map((col) => (
<th key={col as string}>{col}</th>
))}
</tr>
</thead>
<tbody>
{data.map((row, index) => (
<tr key={index}>
{columns.map((col) => (
<td key={col as string}>{row[col]}</td>
))}
</tr>
))}
</tbody>
</table>
);
};
// Usage with user data
const UserTable = () => {
const users = [
{ id: 1, name: "Alice", age: 25 },
{ id: 2, name: "Bob", age: 30 },
];
return <Table data={users} columns={["id", "name", "age"]} />;
};
export default UserTable;const transformData = <T,>(data: T[], transformFn: (item: T) => string): string[] => {
return data.map(transformFn);
};
// Usage with numbers
const numbers = [1, 2, 3];
const transformedNumbers = transformData(numbers, (num) => `Number: ${num}`);
console.log(transformedNumbers); // ["Number: 1", "Number: 2", "Number: 3"]import { TouchableOpacity, Text } from "react-native";
interface ButtonProps<T> {
value: T;
onPress: (value: T) => void;
}
const GenericButton = <T,>({ value, onPress }: ButtonProps<T>) => {
return (
<TouchableOpacity onPress={() => onPress(value)}>
<Text>{String(value)}</Text>
</TouchableOpacity>
);
};
// Usage with numbers
<GenericButton value={10} onPress={(num) => console.log(num)} />;