Have you ever built a React application and ended up with components that felt cluttered or hard to understand? You might be mixing presentation logic (how things look) with business logic (how things work). This can make your code harder to maintain and test.
The Container and Presentation pattern is a way to separate these concerns, leading to cleaner, more manageable components.
Imagine a restaurant menu. The menu itself (the presentation component) shows you the dishes (data) and their descriptions. But the kitchen (the container component) is where the actual cooking (business logic) happens. They work together to deliver a delicious meal (functioning React application)!
In React, the container component handles:
Fetching data from an API or store
Performing calculations or computations
Managing application state
The presentation component handles:
Displaying the data or computed values on the UI
Responding to user interactions (like button clicks)
Improved Readability: Separating concerns makes your code easier to understand and follow.
Increased Reusability: Presentation components can be reused across different parts of your application.
Easier Testing: You can test container and presentation components independently.
An example of Container and presentation pattern is shown below:
import React, { useEffect } from "react";
import CharacterList from "./CharacterList";
const StarWarsCharactersContainer: React.FC = () => {
const [characters, setCharacters] = useState<Character>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<boolean>(false);
const getCharacters = async () => {
setIsLoading(true);
try {
const response = await fetch(
"https://akabab.github.io/starwars-api/api/all.json",
);
const data = await response.json();
setIsLoading(false);
if (!data) return;
setCharacters(data);
} catch (err) {
setError(true);
} finally {
setIsLoading(true);
}
};
useEffect(() => {
getCharacters();
}, []);
return (
<CharacterList loading={loading} error={error} characters={characters} />
);
};
export default StarWarsCharactersContainer;
// the component is responsible for displaying the characters
import React from "react";
import { Character } from "./types";
interface CharacterListProps {
loading: boolean;
error: boolean;
users: Character[];
}
const CharacterList: React.FC<CharacterListProps> = ({
loading,
error,
characters,
}) => {
if (loading && !error) return <div>Loading...</div>;
if (!loading && error)
return <div>error occurred.unable to load characters</div>;
if (!characters) return null;
return (
<ul>
{characters.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default CharacterList;
Great to see you here! Subscribe for more content like this delivered straight to your inbox, and let's chat in the comments. Share your thoughts and experiences!