React电影列表日期降序排序与评分单次增减问题求助
电影列表功能修复与扩展
一、实现点击date表头按日期降序排序
- 在组件state中新增排序状态,记录当前排序字段和顺序:
this.state = { movies: [/* 原电影数据 */], sortKey: 'rating', // 默认按rating排序 sortOrder: 'asc' // 默认升序 } - 移除constructor中直接修改state的排序代码,改为调用统一的排序函数初始化
- 编写通用排序函数,支持切换排序字段和顺序:
handleSort = (key) => { // 点击当前排序字段则切换顺序,点击date默认降序,点击其他字段默认升序 const newOrder = this.state.sortKey === key ? (this.state.sortOrder === 'asc' ? 'desc' : 'asc') : (key === 'date' ? 'desc' : 'asc'); // 复制数组避免修改原state数据 const sortedMovies = [...this.state.movies].sort((a, b) => { if (key === 'date') { return newOrder === 'desc' ? b.date - a.date : a.date - b.date; } else if (key === 'rating') { return newOrder === 'asc' ? a.rating - b.rating : b.rating - a.rating; } return 0; }); this.setState({ movies: sortedMovies, sortKey: key, sortOrder: newOrder }); } - 修改表头渲染逻辑,给所有表头绑定点击事件,并添加排序箭头标识:
Object.keys(this.state.movies[0]).map((elem, ind) => { return ( <th key={ind} onClick={() => this.handleSort(elem)} style={{cursor: 'pointer'}} > {elem} {this.state.sortKey === elem && (this.state.sortOrder === 'desc' ? ' ↓' : ' ↑')} </th> ) })
二、修复评分按钮无限触发问题
问题根源是直接修改了state中的原对象,导致React状态更新异常。必须通过创建新数组/对象的方式更新状态:
- 修改
increment函数:increment = (movie) => { const updatedMovies = this.state.movies.map(m => { if (m.id === movie.id) { // 复制原对象并修改rating,不直接修改原数据 return {...m, rating: m.rating + 1}; } return m; }); this.setState({movies: updatedMovies}); } - 修改
decrement函数:decrement = (movie) => { const updatedMovies = this.state.movies.map(m => { if (m.id === movie.id) { return {...m, rating: m.rating - 1}; } return m; }); this.setState({movies: updatedMovies}); } - 修改
remove函数:remove = (index) => { // 通过slice生成新数组,替代splice修改原数组 const updatedMovies = [...this.state.movies.slice(0, index), ...this.state.movies.slice(index + 1)]; this.setState({movies: updatedMovies}); } - 将所有类方法改为箭头函数,避免手动绑定this的繁琐操作
完整修改后的代码
import React from "react"; class App extends React.Component { constructor() { super() this.state = { movies: [ { id: 1, name: "Deadpool", date: 2016, time: 108, genre: 'action', rating: 5 }, { id: 2, name: "The Avengers", date: 2012, time: 143, genre: 'action', rating: 4 }, { id: 3, name: "Slayers", date: 2022, time: 88, genre: 'fantasy,comedy', rating: 3 }, ], sortKey: 'rating', sortOrder: 'asc' } // 初始化按rating升序排序 this.handleSort('rating'); } handleSort = (key) => { const newOrder = this.state.sortKey === key ? (this.state.sortOrder === 'asc' ? 'desc' : 'asc') : (key === 'date' ? 'desc' : 'asc'); const sortedMovies = [...this.state.movies].sort((a, b) => { if (key === 'date') { return newOrder === 'desc' ? b.date - a.date : a.date - b.date; } else if (key === 'rating') { return newOrder === 'asc' ? a.rating - b.rating : b.rating - a.rating; } return 0; }); this.setState({ movies: sortedMovies, sortKey: key, sortOrder: newOrder }); } star(i) { let arr = new Array(i); return arr.fill("*"); } remove = (index) => { const updatedMovies = [...this.state.movies.slice(0, index), ...this.state.movies.slice(index + 1)]; this.setState({movies: updatedMovies}); } increment = (movie) => { const updatedMovies = this.state.movies.map(m => { if (m.id === movie.id) { return {...m, rating: m.rating + 1}; } return m; }); this.setState({movies: updatedMovies}); } decrement = (movie) => { const updatedMovies = this.state.movies.map(m => { if (m.id === movie.id) { return {...m, rating: m.rating - 1}; } return m; }); this.setState({movies: updatedMovies}); } render() { return <> <h1>Cinemas</h1> <table className="table table-dark table-striped"> <thead> <tr> { Object.keys(this.state.movies[0]).map((elem, ind) => { return ( <th key={ind} onClick={() => this.handleSort(elem)} style={{cursor: 'pointer'}} > {elem} {this.state.sortKey === elem && (this.state.sortOrder === 'desc' ? ' ↓' : ' ↑')} </th> ) }) } <th>stars</th> </tr> </thead> <tbody> { this.state.movies.map((elm,index) => { return <tr key={elm.id}> <td>{elm.id}</td> <td> {elm.name} <button className="btn btn-primary ms-4" onClick={() => this.remove(index)}>del</button> </td> <td>{elm.date}</td> <td>{elm.time}</td> <td>{elm.genre}</td> <td>{elm.rating}</td> <td> {this.star(elm.rating)} <button className="btn btn-primary ms-4" onClick={() => this.increment(elm)}>Increment</button> <button className="btn btn-primary ms-4" onClick={() => this.decrement(elm)}>Decrement</button> </td> </tr> }) } </tbody> </table> </> } } export default App
内容的提问来源于stack exchange,提问作者Andrey
相关产品推荐
相关产品推荐

