Недавно я начал использовать React и Redux для восстановления одного из основных компонентов на сайте Gogobot.
Чтобы лучше понять проблему, вот несколько снимков экрана одного из компонентов на этой странице.
Не разбираясь в деталях компонента, вы можете увидеть, что компоненты имеют много общего:
- Подсчет метки, которая отображается / скрывается в зависимости от количества элементов, выбранных мной в фильтре.
- Выпадающий список, который открывается при нажатии значка.
- После нажатия он отправляет событие (действие) и запрашивает данные из
- После нажатия он отправляет событие (действие) и запрашивает данные с сервера на основе нового фильтра.
Садясь разрабатывать этот компонент, я понял, что ** поведение **, разделяемое каждым из них, требует ** компонента более высокого порядка **, который будет определять поведение и обертывать все «дочерние» компоненты.
Выполнение этого с помощью чистого 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 }); }
Вот и все.
Теперь вы можете поделиться схожей логикой компонентов.
Преимущества
Очевидные преимущества этого подхода заключаются в том, что если у вас есть общее поведение для набора компонентов, вы подключаете только «базу» к хранилищу и управляете всем из нее. Остальные ваши компоненты - это просто «тупые компоненты», которым вводят поведение.
Код намного чище, и есть единая точка входа для действий / изменений состояния в системе, это значительно упрощает отладку и тестирование и в целом делает код более читаемым.