> For the complete documentation index, see [llms.txt](https://max-frontend.gitbook.io/redux-course-ru-v2/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://max-frontend.gitbook.io/redux-course-ru-v2/sozdanie/optimizatsiya-refaktoring/optimizatsiya-pererisovok.md).

# Оптимизация перерисовок

У нас есть 2 компонента `<User />` и `<Page />`. Мы специально сделали для них два редьюсера, чтобы обновлять их независимо! А у нас? А у нас `<User />` каждый раз обновляется при обновлении `<Page />` и наоборот.

Добавьте console.log в render метод у `<User />`:

*src/components/User.js*

```jsx
...
render() {
  console.log('<User/> render')
  return <div className="ib user">{this.renderTemplate()}</div>
}
...
```

![user-render-console-log](/files/-LvLnQOgoxfmkHKpza-0)

Перерисовка компонента User происходит постоянно. Это не влияет на производительность нашего мини-приложения, однако, мы не готовы с этим мириться.

Представьте дашборд (панель) с большим количеством виджетов, информация в которых обновляется по событиям от бэкэнда. Если каждый виджет будет перерисовывать полностью весь дашборд, то это будет крайне некрасиво (как для юзера, так и для производительности).

Чтобы такого не было, мы должны каждую отдельную сущность приложения класть в отдельный контейнер.

Будем исправлять, для этого:

* `<App />` становится тупым компонентом, который рендерит 2 контейнера:
  * `<PageContainer />`
  * `<UserContainer />`

Данные контейнеры - просто обертки над нашими компонентами, в которых мы "подключаемся (*connect*) к Redux".

Так же, я сразу заменю название у экшенов внутри mapDispatchToProps: уберу оттуда частичку *Action*.

В остальном, мы просто "разносим" то, что было в `<App />` по раздельным контейнерам.

*src/index.js*

```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { store } from './store/configureStore'
import App from './components/App' // изменили путь

import registerServiceWorker from './registerServiceWorker'

import './index.css'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
registerServiceWorker()
```

*src/components/App.js*

```jsx
import React, { Component } from 'react'
import UserContainer from '../containers/UserContainer' // изменили импорт
import PageContainer from '../containers/PageContainer' // изменили импорт

class App extends Component {
  render() {
    return (
      <div className="app">
        <PageContainer />
        <UserContainer />
      </div>
    )
  }
}

export default App
```

*src/containers/PageContainer.js*

```jsx
import React from 'react'
import { connect } from 'react-redux'
import { Page } from '../components/Page'
import { getPhotos } from '../actions/PageActions'

class PageContainer extends React.Component {
  render() {
    const { page, getPhotos } = this.props
    return (
      <Page
        photos={page.photos}
        year={page.year}
        isFetching={page.isFetching}
        error={page.error}
        getPhotos={getPhotos}
      />
    )
  }
}

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

const mapDispatchToProps = dispatch => {
  return {
    getPhotos: year => dispatch(getPhotos(year)),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(PageContainer)`
```

Как вы могли заметить, все что касалось `<Page />` хранится в отдельном контейнере: подписка на часть стора, экшен, пропсы...

То же самое, делаем для `<UserContainer />`

*src/containers/UserContainer.js*

```jsx
import React from 'react'
import { connect } from 'react-redux'
import { User } from '../components/User'
import { handleLogin } from '../actions/UserActions'

class UserContainer extends React.Component {
  render() {
    const { user, handleLogin } = this.props
    return (
      <User
        name={user.name}
        error={user.error}
        isFetching={user.isFetching}
        handleLogin={handleLogin}
      />
    )
  }
}

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

const mapDispatchToProps = dispatch => {
  return {
    handleLogin: () => dispatch(handleLogin()),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(UserContainer)
```

Теперь внимание: в компоненте *App* есть два "независимых компонента". Сейчас при изменении данных в редьюсере для *Page* - *User* перерисовываться не будет. *App* тоже, само собой. *App* у нас вообще не будет перерисовываться более при таком раскладе.

Снова покликаем по кнопкам (*console.log* в `<User />` остался):

![user-not-re-renders-console-log](/files/-LvLnQOoeajCIQbueqYz)

Еще раз заострю внимание: мы не просто сделали хорошо, мы сделали супер-хорошо! Render - обычно самая дорогая операция. Вызывать "перерисовку" каждого "кусочка" приложения нужно осознанно. Всегда проверяйте (например, так же банально с помощью `console.log`) сколько раз у вас что рендерится, и нет ли чего лишнего.

Давайте заодно здесь быстренько исправим отрисовку кнопок в `<Page />`

*src/components/Page.js*

```jsx
...

export class Page extends React.Component {
  onBtnClick = e => {
    ...
  }
  renderButtons = () => {
    const years = [2018, 2017, 2016, 2015, 2014]

    return years.map((item, index) => { // [1]
      return (
        <button key={index} className="btn" onClick={this.onBtnClick}>
          {item}
        </button>
      )
    })
  }
  renderTemplate = () => {
    ...
  }

  render() {
    const { year, photos } = this.props
    return (
      <div className="ib page">
        <p>{this.renderButtons()}</p>
        <h3>
          {year} год [{photos.length}]
        </h3>
        {this.renderTemplate()}
      </div>
    )
  }
}
...
```

(*Добавьте по вкусу щепотку `margin` для `.btn`*)

\[1] Использовать в данной ситуации *index* для *key* плохо?. В данном случае - не плохо. Напоминаю, что индекс в качестве ключа плохо использовать, когда у вас элементы меняются местами. Справедливости ради, здесь в качестве индекса можно было бы использовать "год", так как главное в индексе - это **уникальность**.

**Итого**: мы научились бережно относится к перерисовкам, а так же закрепили на практике вопрос зачем разбивать редьюсер на маленькие редьюсеры.

[Исходный код](https://github.com/maxfarseer/redux-course-ru-v2/tree/chp13-optimize-re-renders).
