cod;nncode. learn. thrive.

Presentational and Container Components in React Redux: Which One to Use When?

Posted Mar 10, 2023

React Redux Presentational and Container Components

React Redux is a popular JavaScript library that allows developers to easily manage state in their React applications. React Redux provides a predictable state container and allows developers to easily share data between components.

Introduction to React Redux and Component Architecture

What is React Redux?

React Redux is a library that provides a predictable and centralized state container for React applications. It allows developers to manage the state of their application in a consistent and efficient manner.

React Redux is built on top of Redux, which is a standalone library that can be used with any JavaScript framework or library. Redux is based on the Flux architecture, which provides a unidirectional data flow and helps to avoid issues with mutable state.

The Importance of Component Architecture

Component architecture is an important concept in React Redux. It involves breaking down your application into smaller, reusable components that can be easily managed and updated.

In React Redux, components are divided into two categories: Presentational Components and Container Components. This division helps to keep your code organized and maintainable.

Presentational VS Container Components in React Redux

What are Presentational Components in React Redux?

Presentational components in React Redux are designed to display data to the user in a visually appealing way. They are typically simple components that only receive data through props and do not handle any state changes. These components are meant to be reusable and easily styled with CSS.

For example, a presentational component in a weather app could display the current temperature, humidity, and weather conditions. It receives this data through props and renders it in a user-friendly way.

What are Container Components in React Redux?

Container components in React Redux are responsible for managing the state of the application and passing data down to presentational components. They are more complex than presentational components and typically handle user interactions and state changes.

For example, a container component in a weather app could manage the user's location and make API calls to fetch weather data based on that location. It would then pass this data down to the presentational components to display.

Understanding the Differences between Presentational and Container Components

The main difference between presentational and container components in React Redux is their responsibilities. Presentational components focus on displaying data, while container components handle the logic and state changes needed to manage that data.

It's important to keep these responsibilities separate to ensure that components are reusable, testable, and easy to maintain. By using a combination of presentational and container components in your React Redux app, you can create a clear and organized codebase that is easy to work with.

Building Presentational Components in React Redux

Presentational Component Best Practices

When building Presentational Components in React Redux, there are several best practices to keep in mind:

  • Keep them small and reusable
  • Only accept props and don't have any side effects
  • Don't manage state or access the Redux store
  • Use descriptive names that reflect their purpose

Example of Presentational Components in React Redux

Let's say we're building a simple shopping cart feature. A presentational component for displaying an individual item in the cart might look like this:

import React from "react";

const CartItem = ({ item, removeItem, updateQuantity }) => {
  const handleQuantityChange = (e) => {
    updateQuantity(item.id, e.target.value);
  };

  const handleRemoveClick = () => {
    removeItem(item.id);
  };

  return (
    <div className="cart-item">
      <h4>{item.name}</h4>
      <p>Price: ${item.price}</p>
      <label htmlFor={`quantity-${item.id}`}>Quantity:</label>
      <input
        id={`quantity-${item.id}`}
        type="number"
        min="1"
        value={item.quantity}
        onChange={handleQuantityChange}
      />
      <button onClick={handleRemoveClick}>Remove</button>
    </div>
  );
};

export default CartItem;

In this example, CartItem is a presentational component that displays information about an item in the shopping cart and provides UI for updating the item's quantity or removing it from the cart.

It receives props such as item (an object representing the item), removeItem (a function passed down from the Cart container component), and updateQuantity (another function passed down from the Cart container component).

Building Container Components in React Redux

Container Component Best Practices

When building container components in React Redux, there are a few best practices to follow:

  • Keep them small and focused on a specific feature or task
  • Connect them to the Redux store using the connect() function
  • Only pass down necessary data as props to child components
  • Dispatch actions to update the state of the Redux store

Example of Container Components in React Redux

Continuing with our shopping cart example, we might have a container component called Cart that manages the state of the shopping cart and passes down data to presentational components. Here's an example of what the Cart container component might look like:

import { useSelector, useDispatch } from "react-redux";
import { removeFromCart, updateQuantity } from "../actions/cartActions";
import CartItem from "../components/CartItem";

const Cart = () => {
  const items = useSelector((state) => state.cart.items);
  const total = useSelector((state) => state.cart.total);
  const dispatch = useDispatch();

  const handleRemoveItem = (id) => {
    dispatch(removeFromCart(id));
  };

  const handleUpdateQuantity = (id, quantity) => {
    dispatch(updateQuantity(id, quantity));
  };

  return (
    <div className="cart">
      <h2>Shopping Cart</h2>
      {items.length === 0 ? (
        <p>Your cart is empty.</p>
      ) : (
        <>
          {items.map((item) => (
            <CartItem
              key={item.id}
              item={item}
              removeItem={handleRemoveItem}
              updateQuantity={handleUpdateQuantity}
            />
          ))}
          <p>Total: ${total}</p>
        </>
      )}
    </div>
  );
};

export default Cart;

In this example, we're using the useSelector hook to select the items and total properties from the Redux store, and the useDispatch hook to get a reference to the dispatch function.

We then define two callback functions, handleRemoveItem and handleUpdateQuantity, which dispatch the appropriate actions using dispatch.

The Cart component then renders a list of CartItem components, passing down the necessary props. If there are no items in the cart, it displays a message instead of the list. Finally, it displays the total price of the items.

Using hooks like useSelector and useDispatch makes it easier to access the Redux store and dispatch actions without having to define a separate mapStateToProps and mapDispatchToProps functions, and it can make the code more concise and easier to read.

Testing React Redux Components

Testing is a critical aspect of software development, and React Redux components are no exception. In this section, we'll discuss how to test both presentational and container components.

Unit Testing Presentational Components

Presentational components are typically simpler and easier to test than container components. Since they're responsible for rendering the UI, you can use snapshot testing to ensure that the component is rendering correctly.

Snapshot testing takes a snapshot of the rendered output and compares it to a previously saved snapshot. If the snapshots match, the test passes. If they don't match, the test fails, and you'll need to update the snapshot to match the new output.

Here's an example of how to test a presentational component using Jest and Enzyme:

import React from "react";
import { shallow } from "enzyme";
import MyComponent from "./MyComponent";

describe("MyComponent", () => {
  it("should render correctly", () => {
    const component = shallow(<MyComponent />);
    expect(component).toMatchSnapshot();
  });
});

In this example, we're using Enzyme's shallow function to create a shallow rendering of the MyComponent component. We then use Jest's toMatchSnapshot function to compare the rendered output to a previously saved snapshot.

Integration Testing Container Components

Container components are more complex than presentational components since they interact with the Redux store and may have side effects.

As a result, integration testing is often necessary to ensure that container components work as expected.

Integration testing involves testing the interaction between components, rather than just the individual components themselves.

Here's an example of how to test a container component using Jest and Enzyme:

import React from "react";
import { Provider } from "react-redux";
import { mount } from "enzyme";
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import MyContainer from "./MyContainer";

const mockStore = configureStore([thunk]);

describe("MyContainer", () => {
  let store;

  beforeEach(() => {
    store = mockStore({
      someReducer: {
        someValue: "value",
      },
    });
  });

  it("should render correctly", () => {
    const component = mount(
      <Provider store={store}>
        <MyContainer />
      </Provider>
    );
    expect(component).toMatchSnapshot();
  });
});

In this example, we're using Enzyme's mount function to create a full rendering of the MyContainer component, which includes any child components.

We're also using the Provider component from React Redux to provide the Redux store to the component.

Before each test, we create a mock Redux store using the configureStore function from the redux-mock-store library. This allows us to simulate the Redux store and test how the component interacts with it.

Finally, we use Jest's toMatchSnapshot function to compare the rendered output to a previously saved snapshot.

Conclusion and Next Steps

React Redux is a powerful tool for building scalable and maintainable web applications. By using the container/presentational pattern, you can create reusable and modular components that are easy to maintain and update. Additionally, Redux provides a centralized data store that makes it easy to manage application state and keep track of changes.

In this article, we've covered the basics of React Redux and component architecture, as well as the differences between presentational and container components. We've also discussed best practices for building and testing both types of components and provided examples of each.

If you're interested in learning more about React Redux, there are many resources available online. The official Redux documentation is a great place to start, and there are many tutorials and courses available on sites like Udemy, Pluralsight, and Codecademy. By mastering React Redux, you'll be well-equipped to build complex and robust web applications that can scale to meet the needs of your users.

Frequently Asked Questions (FAQ)

What is the difference between presentational and container components?

Presentational components are concerned with how things look, while container components are concerned with how things work. Presentational components receive data and callbacks as props and use them to render UI elements, while container components manage the state of the application and pass data and callbacks to presentational components as props.

Why is component architecture important in React Redux?

Component architecture is important in React Redux because it allows you to break down complex applications into smaller, more manageable pieces. By using the container/presentational pattern, you can create reusable and modular components that are easy to maintain and update. Additionally, Redux provides a centralized data store that makes it easy to manage application state and keep track of changes.

What is the best way to test React Redux components?

The best way to test React Redux components is to use a combination of unit tests and integration tests. Unit tests are used to test individual units of code in isolation, while integration tests are used to test how multiple units of code work together. For presentational components, you can use Jest or other testing frameworks to write unit tests. For container components, you can use tools like Enzyme or React Testing Library to write integration tests.

What are some best practices for building React Redux components?

Some best practices for building React Redux components include keeping presentational components as simple as possible, separating concerns between presentational and container components, and using container components to manage the state of the application. Additionally, you should strive to make your components reusable and easy to test, and avoid coupling components to specific data sources or APIs.

How can I learn more about React Redux?

There are many resources available online for learning React Redux, including the official Redux documentation, tutorials and courses on sites like Udemy, Pluralsight, and Codecademy, and community resources like Stack Overflow and Reddit. Additionally, attending conferences and meetups can be a great way to learn from other developers and stay up-to-date on the latest trends and best practices.

Further Resources

React 19: New Features List [Interview Ready]

Get interview-ready with our comprehensive guide on React 19, covering its groundbreaking advancements, new features, improved performance, and backward compatibility.

Read Here

Git How to Stash

The `git stash` command is used to stash changes in the working directory. This command saves changes in the stash stack, which can later be applied or popped.

Read Here

CRUD Operations in ReactJS Without API: GitHub Code Step-by-Step Example 2024

This article dives into implementing CRUD operations specifically in ReactJS without relying on an external API, providing a comprehensive step-by-step guide and a GitHub code example.

Read Here

Table Pagination tutorial in Reactjs using Server Side API data with Paginate, CSS example

Master the art of React pagination! Learn React.js pageable and paginate, style it with CSS, fetch data from APIs, and even implement server-side pagination with Node.js. Explore practical examples and level up your web development skills today.

Read Here

JavaScript Object Creation: Mastering Classes and Prototypes for Efficiency

Explore different methods of creating objects in JavaScript, with a focus on the 'class' keyword. Learn when to use each approach and the benefits they offer.

Read Here
Your feedback is our favorite notification! Share your thoughts about this page and make us smile.