React is a powerful JavaScript library for building user interfaces. In this blog post, we’ll explore how to create a master-detail page using the Fetch API for data fetching, React Context for state management, and TypeScript for static typing.
Understanding React Context
In React, Context is a mechanism that allows you to share values (like state or functions) between components without having to pass them explicitly through each level of the component tree. This can be particularly useful when dealing with deeply nested components or when certain values need to be accessible by multiple components.
Why Use Context?
Consider a scenario where multiple components in your application need access to the same data or functionality. Traditionally, you might pass this data down as props through each intermediate component, leading to a prop-drilling problem. Context provides an elegant solution to this problem by allowing you to establish a “global” state that can be consumed by any component in the tree without explicit prop passing.
Introducing Context in the Example
In the provided example, we used React Context to manage the selected user and the list of users. The UserContext
file defines a UserProvider
component that wraps its children with a context provider. This provider makes the context values (selected user, list of users, and related functions) accessible to any child component that subscribes to this context.
Step 1: Set Up React App with TypeScript
Start by creating a new React app with TypeScript using Create React App:
npx create-react-app user-management --template typescript
cd user-management
Step 2: Create UserContext
Create a UserContext.tsx
file to manage the selected user state using React Context.
// UserContext.tsx
import React, { createContext, useState, ReactNode } from 'react';
interface User {
id: number;
name: string;
email: string;
// Add additional fields if needed
}
interface UserContextProps {
selectedUser: number | null;
selectUser: (userId: number) => void;
users: User[];
fetchUsers: () => Promise<void>;
}
export const UserContext = createContext<UserContextProps | undefined>(undefined);
interface UserProviderProps {
children: ReactNode;
}
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [selectedUser, setSelectedUser] = useState<number | null>(null);
const [users, setUsers] = useState<User[]>([]);
const selectUser = (userId: number) => {
setSelectedUser(userId);
};
const fetchUsers = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Error fetching users:', error);
}
};
return (
<UserContext.Provider value={{ selectedUser, selectUser, users, fetchUsers }}>
{children}
</UserContext.Provider>
);
};
Consuming Context in Components Components such as
UserList
andUserDetails
then consume this context using theuseContext
hook. This allows them to access and interact with the shared state without the need for prop drilling.
Step 3: Create UserList Component
Now, let’s create a UserList.tsx
component to display the list of users.
// UserList.tsx
import React, { useContext, useEffect } from 'react';
import { UserContext } from './UserContext';
const UserList: React.FC = () => {
const { users, selectUser, fetchUsers } = useContext(UserContext);
useEffect(() => {
fetchUsers();
}, [fetchUsers]);
return (
<div>
<h2>User List</h2>
<ul>
{users.map((user) => (
<li key={user.id} onClick={() => selectUser(user.id)} style={{ cursor: 'pointer' }}>
{user.name}
</li>
))}
</ul>
</div>
);
};
export default UserList;
Step 4: Create UserDetails Component
Next, create a UserDetails.tsx
component to display the details of the selected user.
// UserDetails.tsx
import React, { useContext, useEffect } from 'react';
import { UserContext } from './UserContext';
const UserDetails: React.FC = () => {
const { selectedUser, users, fetchUsers } = useContext(UserContext);
const user = users.find((user) => user.id === selectedUser);
useEffect(() => {
if (!user) {
fetchUsers();
}
}, [user, fetchUsers]);
if (!user) {
return <p>Select a user from the list to view details.</p>;
}
return (
<div>
<h2>User Details</h2>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
{/* Additional user details */}
</div>
);
};
export default UserDetails;
Step 5: Use Components in App.tsx
Now, integrate these components in the App.tsx
file.
// App.tsx
import React from 'react';
import UserList from './UserList';
import UserDetails from './UserDetails';
import { UserProvider } from './UserContext';
const App: React.FC = () => {
return (
<UserProvider>
<div>
<h1>User Management App</h1>
<UserList />
<UserDetails />
</div>
</UserProvider>
);
};
export default App;
Step 6: Run Your App
Start your React app:
npm start
Visit http://localhost:3000
in your browser. You should see a list of users on the left side. Clicking on a user will display their details on the right side.