เมื่อเร็วๆ นี้ ฉันเริ่มใช้ React และ Redux เพื่อสร้างหนึ่งในองค์ประกอบหลักบนเว็บไซต์ Gogobot
เพื่อให้เข้าใจปัญหาได้ดีขึ้น ต่อไปนี้เป็นภาพหน้าจอของส่วนประกอบใดส่วนประกอบหนึ่งในหน้านั้น
หากไม่เข้าใจรายละเอียดขององค์ประกอบจริงๆ คุณจะเห็นว่าส่วนประกอบต่างๆ มีหลายสิ่งหลายอย่างร่วมกัน:
- นับป้ายกำกับที่แสดง/ซ่อนตามจำนวนรายการที่ฉันเลือกจากตัวกรอง
- ดรอปดาวน์ที่เปิดขึ้นเมื่อคลิกที่ไอคอน
- เมื่อคลิกแล้ว จะส่งเหตุการณ์ (การกระทำ) และขอข้อมูลจาก
- เมื่อคลิกแล้ว ระบบจะส่งเหตุการณ์ (การกระทำ) และขอข้อมูลจากเซิร์ฟเวอร์ตามตัวกรองใหม่
เมื่อนั่งลงเพื่อออกแบบส่วนประกอบนี้ ฉันพบว่า **พฤติกรรม** ที่ใช้ร่วมกันระหว่างแต่ละองค์ประกอบนั้นจำเป็นต้องมี **ส่วนประกอบลำดับที่สูงกว่า** ที่จะกำหนดพฤติกรรมและรวมส่วนประกอบ "รอง" ทั้งหมด
การทำสิ่งนี้ด้วย Pure 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 }); }
เกี่ยวกับมัน.
ตอนนี้คุณสามารถแบ่งปันตรรกะของส่วนประกอบที่คล้ายกันได้แล้ว
ประโยชน์
ประโยชน์ที่ชัดเจนของแนวทางนี้คือ หากคุณมีพฤติกรรมการใช้ร่วมกันสำหรับชุดส่วนประกอบ คุณจะเชื่อมต่อ "ฐาน" กับร้านค้าเท่านั้น และคุณจะจัดการทุกอย่างจากร้านค้านั้น ส่วนประกอบที่เหลือของคุณเป็นเพียง "ส่วนประกอบที่โง่" และถูกแทรกซึมไปด้วยพฤติกรรม
โค้ดสะอาดกว่ามากและมีจุดเข้าเพียงจุดเดียวสำหรับการดำเนินการ/การเปลี่ยนแปลงสถานะในระบบ ซึ่งช่วยลดความยุ่งยากในการดีบักและการทดสอบจำนวนมาก และโดยรวมแล้วทำให้โค้ดอ่านได้ง่ายขึ้น