Container Component Pattern in React

 - Richa Pujara

Intern at Back2.Dev

{Richa Pujara is fully pure}

{ Why? }

& Container Component Pattern

  • What are these?
  • How to use them?
  • Applicability IRL
  • Storybook - Testing Buddy
  • My thoughts

{ Overview }

{  What is it? }

Pure component (props)

 * Display
 * User interaction

Container

 * Fetches data

 * Saves data

Storybook

 * Provides different data sets

 * Logs actions (eg save)

Pure component (props)

 * Display
 * User interaction

{ A way of writing code.. }

import React from 'react';

export default function DogImages() {
  const [dogs, setDogs] = React.useState([])

  React.useEffect(() => {
    fetch("https://dog.ceo/api/breed/labrador/images/random/6")
      .then(res => res.json())
      .then(jsonRes => setDogs(jsonRes.message));
  }, [])
  const myStyle = {
    border: '1px solid black',
    width: "80vw",
    height: "80vh",
    backgroundColor: "grey",
    overflow: "scroll",
    textAlign: "center",
  }
  return (
    <>
      <div>
        <h2 className="heading">Dogs Images</h2>
      </div>
      <div style={myStyle}>
        {dogs.map((dog, i) => <img src={dog} key={i} alt="Dog" width={'100%'} height={'100%'} />)}
      </div>
    </>
  )
}
# PRESENTING CODE
// DogsUI.js -- Presentational Component
import React from "react";
import PropTypes from 'prop-types'
function DogImages({ dogs, ...props }) {
  const myStyle = {
    border: props.border || '1px solid black',
    width: props.width || "80vw",
    height: props.height || "80vh",
    backgroundColor: props.backgroundColor || "grey",
    overflow: "scroll",
    textAlign: props.alignment || "center",
  }
  return (
    <div style={myStyle}>
      {dogs.map((dog, i) => {
        <img src={dog} key={i} alt="Dog" width={props.imgwidth || '100%'} height={props.imgheight || '100%'} />
      })}
    </div >
  )
}

export default DogImages
# PRESENTATIONAL COMPONENT

{A Better way of doing it}

// dogsContainer.js -- Container Component
import React from 'react';
import DogImages from './DogsUI'

export default function DogImagesContainer() {

  const [dogs, setDogs] = React.useState([])

  React.useEffect(() => {
    fetch("https://dog.ceo/api/breed/labrador/images/random/6")
      .then(res => res.json())
      .then(jsonRes => setDogs(jsonRes.message))
  }, [])

  return <DogImages dogs={dogs} />;
# CONTAINER COMPONENT

Container

 * Fetches data

 * Saves data

Pure component (props)

 * Display
 * User interaction

Context (shared state)

Container

 * Fetches data

 * Saves data

List

Context / shared state (also pure)

Add

Edit

View

 { Applicability IRL }

Storybook

import React from 'react';
import Dogs from './DogsUI';
export default {
  title: 'Dogs',
  component: Dogs,
  argTypes: {
    backgroundColor: { control: 'color' },
    height: { control: 'select', options: ['50vh', '60vh', '70vh', '80vh', '90vh', '100vh'] },
    imgheight: { control: 'select', options: ['50px', '100px', '150px', '200px', '250px', '300px'] },
    width: { control: 'select', options: ['50%', '60%', '70%', '80%', '90%', '100%'] },
    imgwidth: { control: 'select', options: ['50%', '60%', '70%', '80%', '90%', '100%'] },
    alignment: { control: 'select', options: ['center', 'left', 'right'] }
  }
};
const Template = (args) => <Dogs {...args} />;

// Test Stories with different scenarios:
export const DogsImages1 = Template.bind({});
DogsImages1.args = {
  dogs: ["https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_2174.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_389.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_5017.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_7133.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_7179.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_7749.jpg"],
};
export const DogsImages2 = Template.bind({});
DogsImages2.args = {
  dogs:["https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_3273.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_5000.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_5471.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_6684.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_7963.jpg", "https:\/\/images.dog.ceo\/breeds\/labrador\/n02099712_8051.jpg"]
};
export const CatsImages3 = Template.bind({});
CatsImages3.args = {
  dogs:["https://cdn2.thecatapi.com/images/3gv.jpg", "https://cdn2.thecatapi.com/images/4cl.gif", "https://cdn2.thecatapi.com/images/b8p.jpg", "https://cdn2.thecatapi.com/images/bvu.jpg", "https://cdn2.thecatapi.com/images/MTczNTkwNA.jpg"],
  border: "1px solid red"
};
# PRESENTING CODE

{ And I think... }

{ Why containers? }

  • Separation of APIs/ App logic from Presentational part

  • Reusability of components

  • Sharing states

  • Makes App structure easier to understand

Answer to a big question..

Thank You...

Container Pattern in React

By richap

Container Pattern in React

  • 34