A Deep Dive into the Presentation Container Pattern with React.js

A Deep Dive into the Presentation Container Pattern with React.js

Using Presentation Container Design makes easy separation and concert b/w UI and logic.

These are reusable solutions to common software design problems that help improve the overall structure of your application.

Take a closer look at one specific design pattern – the Presentation Container Pattern – with practical examples in React.js.

The Presentation Container Design Pattern

let’s dive into one specific design pattern: the Presentation Container Pattern. This pattern is especially useful in the context of UI development in modern JavaScript frameworks like React.js.

What is the Presentation Container Pattern?

In a nutshell, the Presentation Container Pattern separates the UI logic from the business logic in your application. It defines two distinct layers:

  1. Presentation Components (UI): These are the components responsible only for displaying data. They don’t contain any business logic. Their role is to focus on how things look and how the user interacts with the interface. They rely on props passed down from container components to render the UI.

  2. Container Components (Logic): These components handle the application's business logic, data fetching, and state management. They pass the necessary data down (by props) to the presentation components as props. The container components don’t handle how things are displayed; instead, they focus on what data needs to be rendered.

This pattern helps break up the complexities of a large application into smaller, more manageable pieces. The separation of concerns between presentation and logic also makes it easier to maintain and scale your application over time.

Why Use the Presentation Container Pattern in React?

React is known for its component-based architecture, where you can break down your UI into small, reusable components. However, as your application grows, it can become difficult to manage the logic and data flow.

Main focus on achieving single responsibility principle

Why this pattern is useful in React development:

  1. Separation of Concerns: Easily do difference b/w logic and ui(user interface), and handle independently.

  2. Improved Reusability: Presentational components become more reusable because they are decoupled from any application-specific logic. Try to make dump component which don’t know, how I get props.

  3. Easier Testing: Since the presentation components are only responsible for rendering UI and don't have any logic, they become much easier to test. You can use Playwright like testing library.

  4. Maintainability: As the application grows, managing business logic separately from UI logic helps you maintain a clean codebase.

How to Implement the Presentation Container Pattern in React?

While this blog is meant to introduce you to the pattern, we’ll be diving into the practical implementation of this design pattern with React in the next section. Stay tuned as we break down the code and see how you can apply the Presentation Container Pattern in your own React projects.

I take an example of form and input

TextInputForm.tsx component only define and use for showing ui. Logical handle by Container part of TextInputFormContainer component.

import Button from "../Button/Button";
import TextInput from "../TextInput/TextInput"; // import from another file.

interface TextInputFormProps {
    inputType: "password" | "text";
    handleShowHideButton: () => void;
    handleSubmitForm: (event: React.FormEvent) => void;
    handleInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
    value: string;
}
// accepting props
function TextInputForm({  
    inputType,
    handleShowHideButton,
    handleSubmitForm,
    handleInputChange,
    value,
}: TextInputFormProps) {
    return (
        <form onSubmit={handleSubmitForm}
            className="flex flex-col space-y-3 py-3 w-[40%] justify-center items-center my-2 "
        >
            <TextInput
                value={value}
                inputType={inputType}
                placeholder="Enter word"
                handleChange={handleInputChange}
                className="border border-blue-400 hover:border-blue-500 transition duration-200 ease-in-out w-full h-10 my-2 px-2"
            />
            <div className="flex space-x-3" >
                <Button
                    type="button"
                    isDisabled={false}
                    variant="secondary"
                    handleClick={handleShowHideButton}
                    text={inputType === "password" ? "Show" : "Hide"}
                />

                <Button
                    type="submit"
                    isDisabled={false}
                    variant="primary"
                    text="Submit"
                />
            </div>
        </form>

    );
}

export default TextInputForm;

TextInputFormContainer .tsx

import React, { useState } from "react";
import { useNavigate } from 'react-router-dom';
import TextInputForm from "./TextInputForm";  // above component file

function TextInputFormContainer() {

    const [inputType, setInputType] = useState<"password" | "text">("password");
    const [value, setValue] = useState("");

    const navigate = useNavigate();

    function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
        setValue(event.target.value);
        console.log(event.target.value);  
    }

    function handleSubmitForm(event: React.FormEvent) {
        event.preventDefault();
        if (value.trim()) {  
            navigate(`/play`, {
                state: {
                    selectedWord: value  
                }
            });
        }

    }

    function handleShowHideButton() {
        setInputType((prev) => prev === "password" ? "text" : "password");
        console.log(inputType);  
    }

    return ( // return the whole TextInputForm component
        <TextInputForm
            inputType={inputType}
            handleInputChange={handleInputChange}
            handleSubmitForm={handleSubmitForm}
            handleShowHideButton={handleShowHideButton}
            value={value}  
        />
    );
}

export default TextInputFormContainer;

The container Component only use for provide the logic or add the logic in TextInputForm. Which’ve some important property which accept by TextInputForm.

It show we render or pass TextInputFormContainer to the parent component and render on screen.

For whole code check github repo code


Conclusion

The Presentation Container Pattern is particularly useful when working with React.js, as it helps separate concerns between UI and business logic, improving both the structure and reusability of your code.