React design patterns (part 2)
Tags: engineering, javascript, react, technology
Published: 2021-06-17 10:32:15

---
title: React design patterns (part 2)
published: true
date: 2021-01-11 08:34:57 UTC
tags: Engineering,JavaScript,React,Technology
canonical_url: https://bugfender.com/blog/react-design-patterns-part-2/
---

This article is the second part of the React Design Patterns article. If you missed the first part, go to part 1 ([link here](https://dev.to/bugfenderapp/react-design-patterns-part-1-2cm6-temp-slug-8540625)) of the series.

This time we’ll be talking about the `Context` pattern, the `Presentational and Container Components` pattern, and the `Compound Components` pattern.

## Context

According to the [React documentation](https://reactjs.org/docs/context.html):

> Context provides a way to pass data through the component tree without having to pass props down manually at every level.

In simple terms, If you have a global state that needs to pass through several component levels, you can use `Context`. For example: if you have a `theme` that influences all the components, `Context` will streamline the process.

**Note.** There is one potential snag to bear in mind when using `Context`: it can make the components less reusable. The `Context` data will be available in the `Provider` scope, so you can’t use it outside the `Provider`. I found a great [video](https://www.youtube.com/watch?v=3XaXKiXtNjw&ab_channel=ReactTraining) that explains this issue and tells you how to avoid ‘prop drilling.’

Let’s see an example of Context in action:

```
import React, { useContext, createContext } from "react";
import "./styles.css";
let data = {
  title: "Welcome"
};
const Context = createContext();

export default function App() {
  return (
    <Context.Provider value={data}>
      <div className="App">
        <Card />
      </div>
    </Context.Provider>
  );
}

const Card = () => {
  return (
    <div className="card">
      <CardItem />
    </div>
  );
};

const CardItem = () => {
  return (
    <div className="CardItem">
      <Title />
    </div>
  );
};

const Title = () => {
  const data = useContext(Context);
  return <h1>{data.title}</h1>;
};
```

As we can see in this (elementary) example, we have three levels of components, and we only use the `data.title` in the last level. This way, we don’t need to pass the props to all the levels.

### A few tips on context syntax

I always apply this syntax when using context. However, there are some things I found out when I wrote it again:

- In the case of “static data” (like the example), we actually don’t need the `Provider`. we can fulfill that function ourselves:

```
let data = {
  title: "Welcome"
};
const Context = createContext(data);

export default function App() {
  return (
    <div className="App">
      <Card />
    </div>
  );
}
```

At the other end of the scale, we can use the `Customer` instead of `useContext`, like this:

```
const Title = () => {
  return (<Context.Consumer>
            {(data) => <h1>{data.title}</h1>}
        </Context.Consumer>);
};
```

## Presentational and Container Components

These components (also known as `Smart And Dumb Components`) are among the best-known React patterns. There are no references to them in the React documentation, but Dan Abramov’s [article](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) provides an excellent guide.

In simple terms, `Presentational And Container Components` refer to the separation of the business logic components from the UI views.

Let’s look at another scenario:

- We need to build a `Card` component.
- Inside the card, we have three other components: `Title`, `Image` and `Button`.
- The button changes the picture after a click on it.

Before we start working on our components, let’s create two folders: ‘Presentational’ and ‘Container.’ Now, let’s build the three `Presentational` components :

**Title.js :**

```
import React from "react";
export default function Title(props) {
  const { children, ...attributes } = props;
  return <h1 {...attributes}>{children}</h1>;
}
```

**Image.js :**

```
import React from "react";
export default function Image(props) {
  const { src, alt } = props || {};
  return <img src={src} alt={alt} />;
}
```

**Button.js :**

```
import React from "react";
export default function Button(props) {
  const { children, ...attributes } = props;
  return <button {...attributes}>{children}</button>;
}
```

Finally, we can build in the Container folder component, known as the `Card`.

**Card.js :**

```
import React, { useEffect, useState } from "react";
import Title from "../Presentational/Title";
import Image from "../Presentational/Image";
import Button from "../Presentational/Button";

export default function Card() {
  const [card, setCard] = useState({});
  const [srcIndex, setSrcIndex] = useState(0);

  useEffect(() => {
    setCard({
      title: "Card Title",
      image: {
        imagesArray: [
          "<https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTh87QN4DkF7s92IFSfm7b7S4IR6kTdzIlhbw&usqp=CAU>",
          "<https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRjFnHdaH1i1m_xOaJfXTyq4anRFwRyCg1p1Q&usqp=CAU>"
        ],
        alt: "card image"
      }
    });
  }, []);
  const { image } = card;
  const changeImage = () =>
    setSrcIndex((index) =>
      index < image.imagesArray.length - 1 ? index + 1 : index - 1
    );
  return (
    <div className="card">
      <Title className="title-black">{card.title && card.title}</Title>
      <Image
        src={image && image.imagesArray[srcIndex]}
        alt={image && image.alt}
      />
      <Button onClick={changeImage}>Change Picture</Button>
    </div>
  );
}

```

If you want to see the full code, check it out [here](https://codesandbox.io/s/presentational-and-container-component-example-9df6h).

**Note!** Many of you may be wondering why you needed to separate into different components. You could just write them inside `Card`, right?

Well when we separate the components, we can reuse them anywhere. But even more importantly, it is much easier to implement other patterns like `HOC` or `Render Props`.

## Compound Components

In my opinion, this is one of the most intricate patterns to understand, but I will try to explain it as simply as I can.

When we talk about `Compound Components`, the most simple way is to think about `select` and `option` in HTML. You can look at them as a group of components that have a basic functionality. There are states that are managed globally (like in the `context` pattern) or from the container (like in `presentational and container` patterns).

**`Compound components`** are really a mixture of these two. It’s almost as if they each have their owned states and they manage them from within.

Let’s look at the next scenario:

- We need to develop `Select` and `Option` components.
- We want the `Option` to be vivid, with different colors.
- The `Option` color will influence the `Select` color.

Let’s see the example:

**App.js**

```
import React from "react";
import "./styles.css";
import Select from "./Select";
import Option from "./Option";

export default function App() {
  return (
    <div>
      <Select>
        <Option.Blue>option 1</Option.Blue>
        <Option.Red>option 2</Option.Red>
        <Option>option 3</Option>
      </Select>
    </div>
  );
}
```

- The `App` renders the `Select` and the `Option` components.
- `Option.Blue` and `Option.Red` are ‘colors components.’

**Option.js**

```
sdsdimport React, { useEffect } from "react";

function Option(props) {
  const { children, style, value, setStyle } = props;
  useEffect(() => {
    if (setStyle) setStyle({ backgroundColor: style.backgroundColor });
  }, [setStyle, style]);
  return (
    <option value={value} style={style}>
      {children}
    </option>
  );
}

Option.Blue = function (props) {
  props.style.backgroundColor = "blue";
  return Option(props);
};

Option.Red = function (props) {
  props.style.backgroundColor = "red";
  return Option(props);
};
export default Option;

```

- Here you can see the Implementation of `Option.Blue` and `Option.Red`. As will be apparent, we render the `Option` component and just add a property to props.
- The `setStyle` comes from `Select`. It’s for changing the select color to the color of the selected option.

**Select.js**

```
import React, { useState } from "react";

export default function Select(props) {
  const { children } = props;
  const [style, setStyle] = useState({});

  const findOptionActive = (e) => {
    const index = e.target.value * 1;
    const optionStyle = { ...e.nativeEvent.target[index].style };
    if (optionStyle) setStyle({ backgroundColor: optionStyle.backgroundColor });
  };

  const childrenWithProps = React.Children.map(children, (child, index) => {
    return React.cloneElement(child, {
      ...child.props,
      value: index,
      setStyle:
        index === 0 && Object.keys(style).length === 0 ? setStyle : null,
      style: { backgroundColor: "white" }
    });
  });

  return (
    <select onChange={findOptionActive} style={style}>
      {childrenWithProps}
    </select>
  );
}

```

- Now, we have a select function with the attributes of `onChange` `style`.
- `findOptionActive` gets the style of the option and changes the style of select accordingly,
- The magic really happens in `childrenWithProps`. Normally, when `Select` receives `children`, we can’t access the child props – but with the help of `React.Children` and `React.cloneElement` we can do it. As you can see, we can pass `value`, `setStyle`, and `style` as props.

To get the [Full Code](https://codesandbox.io/s/compound-components-xw3b2?file=/src/App.js), click here.

This exercise gives you good practice, and if you want to try it yourself (maybe in another pattern), add your solution in a comment below.

## Conclusion

This article was intended to show you different patterns in React. You don’t need to use any of the patterns if you don’t want to, but it’s good for a developer to know design patterns on any framework or language, to understand different syntax levels when they see a new codebase.

I hope you enjoyed the tutorial and learned something new. If you know any other pattern or have further information on any of the topics mentioned in the article, please add a comment below.

# Before we go

Bugfender is a tool that helps you finding errors in your production apps. We strongly believe in sharing knowledge and that’s why we create articles like this one. If you liked it, help us to continue creating content by sharing this article or [signing up in Bugfender](https://dashboard.bugfender.com/signup).