Недавно я начал использовать React и Redux для восстановления одного из основных компонентов на сайте Gogobot.

Чтобы лучше понять проблему, вот несколько снимков экрана одного из компонентов на этой странице.

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

  1. Подсчет метки, которая отображается / скрывается в зависимости от количества элементов, выбранных мной в фильтре.
  2. Выпадающий список, который открывается при нажатии значка.
  3. После нажатия он отправляет событие (действие) и запрашивает данные из
  4. После нажатия он отправляет событие (действие) и запрашивает данные с сервера на основе нового фильтра.

Садясь разрабатывать этот компонент, я понял, что ** поведение **, разделяемое каждым из них, требует ** компонента более высокого порядка **, который будет определять поведение и обертывать все «дочерние» компоненты.

Выполнение этого с помощью чистого React довольно очевидно, поэтому я не буду вдаваться в подробности, этот пост будет о том, как сделать это с помощью Redux, поскольку компонент более высокого порядка связан с отправкой, хранением и состоянием.

Выполнение

// src/components/Filters/FilterWrapper/index.js
import React, { Component } from ‘react’;
import { bindActionCreators } from ‘redux’;
import { connect } from ‘react-redux’;
function FilterWrapper(ComposedFilter, filterInfo) {
 class BaseFilter extends Component {
 constructor() {
 super();
 this.state = {
 count: 0
 };
 this.onCheckboxChange = this.onCheckboxChange.bind(this);
 }
onClick(e) {
 
 }
onCheckboxChange(e) {
 
 }
render() {
 let countLabel = this.state.count > 0 ?
 <span>{ this.state.count }</span> :
 null;
return(
 <div className=”filterDetailsWrapper”>
 <div className=”filterTotalCount”>
 { countLabel }
 </div>
 <div className=”optionsDropDownContainer”>
 <ComposedFilter
 {…this.state}
 {…this.props}
 onCheckboxChange={ this.onCheckboxChange }
 />
 </div>
 </div>
 );
 }
 }
function mapStateToProps(state) {
 // REDACTED
 return {};
 }
function mapDispatchToProps(dispatch) {
 return {
 …bindActionCreators(actions, dispatch)
 };
 }
 return connect(mapStateToProps, mapDispatchToProps)(BaseFilter);
}
export default FilterWrapper;

Давайте объясним, что здесь происходит ...

Мы создаем функцию, которая обертывает компонент и определяет некоторое поведение. Это общее поведение для всех обернутых компонентов. В этом примере у нас есть метка счетчика только для примера, но вы, очевидно, можете расширить ее до чего угодно.

Давайте посмотрим на обернутый компонент (HotelClass) для этого примера.

// src/components/Filters/HotelClass/index.js
import React, { Component } from ‘react’;
import ReactDOM from ‘react-dom’;
import BaseFilterWrapper from ‘../BaseFilterWrapper’;
class HotelClass extends Component {
 render() {
 return(
 <div className=”hotelClassOptions”>
 <ul>
 <li className=”optionsdropdown”>
 <label className=”optionTitle”>5</label>
 <input onChange={ this.props.onCheckboxChange } type=”checkbox” value=”5" />
 </li>
 <li className=”optionsdropdown”>
 <label className=”optionTitle”>4</label>
 <input onChange={ this.props.onCheckboxChange } type=”checkbox” value=”4" />
 </li>
 </ul>
 </div>
 )
 }
}
let filterInfo = {
 name: ‘hotel_class’,
 class_name: ‘hotelClass’,
 title: ‘Hotel Class’
};
export default BaseFilterWrapper(HotelClass, filterInfo);

Как видите, при изменении флажка он вызывает this.props.onCheckboxChange, который поступает от компонента более высокого порядка и, в свою очередь, вызывает там поведение.

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

Теперь давайте реализуем логику, чтобы отображать метку счетчика, когда мы устанавливаем флажки, и скрывать его, если счетчик равен 0.

onCheckboxChange(e) {
 let { count } = this.state;
 var { checked, value } = e.target;
 
 if (checked) {
 count += 1;
 } else {
 count -= 1;
 }
 
 this.setState({
 count
 });
}

Вот и все.

Теперь вы можете поделиться схожей логикой компонентов.

Преимущества

Очевидные преимущества этого подхода заключаются в том, что если у вас есть общее поведение для набора компонентов, вы подключаете только «базу» к хранилищу и управляете всем из нее. Остальные ваши компоненты - это просто «тупые компоненты», которым вводят поведение.

Код намного чище, и есть единая точка входа для действий / изменений состояния в системе, это значительно упрощает отладку и тестирование и в целом делает код более читаемым.