Контейнеры и компоненты

Прежде чем мы разобьем App.js на компоненты <User /> и <Page /> хотелось бы отметить про способ разделения на "компоненты" и "контейнеры", иначе называемый: деление на "глупые" и "умные" компоненты, "Presentational" и "Container" и быть может как-то еще.

Позволю себе в очередной раз прибегнуть к офф.документации и перевести таблицу различий, которая отлично и кратко отражает суть.

Магия таблиц обычно проявляется не сразу. Если переписать наше приложение, а потом взглянуть сюда еще раз - многое станет гораздо яснее. Предлагаю так и поступить. Поехали!

Установим prop-types и создадим компоненты.

npm install --save prop-types

src/components/User.js

import React from 'react'
import PropTypes from 'prop-types'

export class User extends React.Component {
  render() {
    const { name } = this.props
    return (
      <div>
        <p>Привет, {name}!</p>
      </div>
    )
  }
}

User.propTypes = {
  name: PropTypes.string.isRequired,
}

src/components/Page.js

import React from 'react'
import PropTypes from 'prop-types'

export class Page extends React.Component {
  render() {
    const { year, photos } = this.props
    return (
      <div>
        <p>
          У тебя {photos.length} фото за {year} год
        </p>
      </div>
    )
  }
}

Page.propTypes = {
  year: PropTypes.number.isRequired,
  photos: PropTypes.array.isRequired,
}

Наш файл App.js - это контейнер (так как подключен к redux). Изменим-с...

src/containers/App.js

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { User } from '../components/User'
import { Page } from '../components/Page'

import './App.css'

class App extends Component {
  render() {
    const { user, page } = this.props
    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">Мой топ фото</h1>
        </header>
        <User name={user.name} />
        <Page photos={page.photos} year={page.year} />
      </div>
    )
  }
}

const mapStateToProps = store => {
  return {
    user: store.user,
    page: store.page,
  }
}

export default connect(mapStateToProps)(App)

Не забудьте так же перенести App.css в src/containers и поменять подключение <App /> в index.js:

...
import App from './containers/App' // изменили путь
...

Так же удалите файл с тестом - App.test.js, так как тесты в данный момент не входят в нашу программу, но возможно, будут добавлены в конце в раздел рецептов. Так или иначе, на сайте есть подробнейшая статья тестирование компонентов с помощью jest и enzyme.

Итого: изучили на практике деление на компоненты и контейнеры.

Исходный код

Last updated