React类组件如何实现按钮按分类筛选商品功能
React类组件实现商品分类筛选方案
核心实现思路
因为筛选按钮和商品列表是两个独立子组件,筛选状态需要在二者之间同步,所以按照React类组件的状态提升原则,把筛选相关逻辑放在两个组件的共同父组件(通常是商品页的页面级组件)统一管理:
- 父组件维护当前选中的分类状态,默认值为
all - 父组件实现分类切换方法、商品过滤逻辑
- 父组件把切换方法传给按钮组件绑定点击事件,把过滤后的商品列表传给商品组件渲染
分文件代码修改
1. 新增/修改共同父组件(示例命名为ShopPage.js)
这个组件是按钮组和商品列表的直接上层容器,负责统一管理状态:
import React, { Component } from 'react'; import { ProductList } from './productList'; import ButtonMenu from './ButtonMenu'; import Products from './products'; class ShopPage extends Component { constructor(props) { super(props); // 初始化状态:默认选中全部分类 this.state = { selectedCategory: 'all' }; // 绑定this指向,类组件自定义方法必须手动绑定 this.handleCategoryChange = this.handleCategoryChange.bind(this); } // 分类切换处理函数 handleCategoryChange(category) { this.setState({ selectedCategory: category }); } // 根据当前选中分类过滤商品 getFilteredProducts() { const { selectedCategory } = this.state; if (selectedCategory === 'all') { return ProductList; } return ProductList.filter(item => item.category === selectedCategory); } render() { const filteredProducts = this.getFilteredProducts(); const { selectedCategory } = this.state; return ( <div className="shop-page"> {/* 传选中状态和切换方法给按钮组 */} <ButtonMenu currentCategory={selectedCategory} onCategoryChange={this.handleCategoryChange} /> {/* 传过滤后的商品列表给商品渲染组件 */} <Products productList={filteredProducts} /> </div> ) } } export default ShopPage;
2. 修改ButtonMenu.js按钮组件
给每个按钮绑定点击事件,点击时触发父组件传过来的切换方法,还可以给当前选中的按钮加高亮样式:
import React, { Component } from 'react'; class ButtonMenu extends Component{ constructor(props) { super(props); this.handleBtnClick = this.handleBtnClick.bind(this); } handleBtnClick(e) { // 拿到按钮上设置的分类value,传给父组件的回调 const category = e.target.value; this.props.onCategoryChange(category); } render(){ const { currentCategory } = this.props; return( <> <div className = "button Menu-container"> <button className = {`main-btn ${currentCategory === 'all' ? 'active' : ''}`} value = "all" onClick={this.handleBtnClick} >ALL</button> <button className = {`main-btn ${currentCategory === 'men' ? 'active' : ''}`} value = "men" onClick={this.handleBtnClick} >Men</button> <button className = {`main-btn ${currentCategory === 'women' ? 'active' : ''}`} value = "women" onClick={this.handleBtnClick} >Women</button> <button className = {`main-btn ${currentCategory === 'jerseys' ? 'active' : ''}`} value = "jerseys" onClick={this.handleBtnClick} >Jerseys</button> <button className = {`main-btn ${currentCategory === 'shirts' ? 'active' : ''}`} value = "shirts" onClick={this.handleBtnClick} >Shirts</button> <button className = {`main-btn ${currentCategory === 'accessories' ? 'active' : ''}`} value = "accessories" onClick={this.handleBtnClick} >Accessories</button> <button className = {`main-btn ${currentCategory === 'collectables' ? 'active' : ''}`} value = "collectables" onClick={this.handleBtnClick} >Collectables</button> </div> </> ) } } export default ButtonMenu;
你可以自己在CSS里给
.main-btn.active类加高亮样式,比如换背景色、加边框,区分选中状态。
3. 修改products.js商品列表组件
不再直接引用原始的ProductList遍历,改为接收父组件传过来的过滤后商品列表渲染:
import React, { Component } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCartPlus } from '@fortawesome/free-solid-svg-icons'; class Products extends Component{ render(){ const { productList } = this.props; return( <> <div className="container prod-cntr" > <div className = "row prod-row"> {productList.map(element =>( <div className = "col-lg-3 prod-col" key={element.id}> <div className = "card card-container"> <img src = {element.image} alt ="product img" className="prod-img"/> <div className="card-body"> <p className ="card-title">{element.product}</p> <p className ="card-text">{element.description}</p> <p className ="prod-price">{element.price} <FontAwesomeIcon icon={faCartPlus} className="prod-carticon"/></p> </div> </div> </div> ))} </div> </div> </> ) } } export default Products;
注意事项
- 类组件自定义的事件方法如果要访问
this.setState,必须在构造函数里手动绑定this指向,或者用类字段箭头函数写法避免绑定 - 不要在子组件里重复维护筛选状态,所有筛选逻辑统一收归父组件,避免出现状态不同步的bug
- 原始商品数据
ProductList作为常量数据源,不要直接修改,过滤时用filter方法返回新数组即可
内容的提问来源于stack exchange,提问作者madQuestions
相关产品推荐
相关产品推荐

