React/Redux排序函数无法更新状态问题求助
让我仔细看了你的代码,Redux状态没更新、UI不刷新的核心原因是Reducer里的Action Type拼写错误,另外还有几个小问题也影响了功能,我帮你逐一修复:
1. 最关键:修复Reducer中的Action Type语法错误
你Reducer里的REMOVE_CAR;和SORT_CARS;这两个case的type字符串多了个分号!而你dispatch的action type是SORT_CARS(没有分号),导致Reducer永远匹配不到这个case,状态自然不会更新。同时REMOVE_CAR的处理逻辑也有问题,state是包含cars数组的对象,不能直接调用filter方法。
修正后的Reducer:
export default (state = { cars: [] }, action) => { switch(action.type) { case 'GET_CARS_SUCCESS': return Object.assign({}, state, { cars: action.payload }); case 'CREATE_CAR_SUCCESS': return Object.assign({}, state, { cars: action.payload }); case 'REMOVE_CAR': // 去掉末尾的分号 return Object.assign({}, state, { cars: state.cars.filter(car => car.id !== action.id) }); // 修正:对state.cars数组做filter,再返回新对象 case 'SORT_CARS': // 去掉末尾的分号 return Object.assign({}, state, { cars: action.cars }); // 注意action里的key是cars,不是payload default: return state; } }
2. 移除组件中的冗余State
你已经通过mapStateToProps把Redux的cars状态映射到了组件props,完全没必要在组件内部再维护cars和sortedCars的state——冗余的state会导致UI和Redux状态不同步,这也是你觉得“props更新但state没同步”的原因。直接用props里的数据就行。
3. 修正componentDidMount的异步逻辑
getCars是异步action,调用它之后不能立刻通过setState同步props,因为此时异步请求还没完成,props还没更新。实际上你根本不需要这行代码,mapStateToProps会自动把Redux的状态变化同步到props,组件会自动重新渲染。
4. 优化排序逻辑(可选)
Array.sort()是原地修改数组的方法,你用concat复制数组是对的,但可以用更简洁的扩展运算符,排序逻辑也可以用localeCompare简化:
sortAlphabetically = () => { console.log("sort button clicked"); // 用扩展运算符复制数组,避免修改原Redux状态里的数组 const sortedCars = [...this.props.cars.cars].sort((a, b) => { const nameA = a.name.toUpperCase(); const nameB = b.name.toUpperCase(); return nameA.localeCompare(nameB); // 替代手动的if-else,逻辑更简洁 }); console.log(sortedCars); this.props.sortCar(sortedCars); }
修正后的完整组件代码
import React, { Component } from 'react'; import { connect } from 'react-redux'; import CarCard from '../components/CarCard'; import CarForm from './CarForm'; import './Cars.css'; import { getCars, sortCar } from '../actions/cars'; class Cars extends Component { sortAlphabetically = () => { console.log("sort button clicked"); const sortedCars = [...this.props.cars.cars].sort((a, b) => { const nameA = a.name.toUpperCase(); const nameB = b.name.toUpperCase(); return nameA.localeCompare(nameB); }); console.log(sortedCars); this.props.sortCar(sortedCars); } componentDidMount() { this.props.getCars(); // 移除不必要的setState,mapStateToProps会自动同步Redux状态到props } render() { return ( <div className="CarsContainer"> <h3>Cars Container</h3> <button onClick={this.sortAlphabetically}>Sort</button> {/* 直接用props里的cars数组渲染,不需要判断存在性(因为Reducer初始状态是{cars: []}) */} {this.props.cars.cars.map(car => ( <CarCard key={car.id} car={car} /> ))} <CarForm /> </div> ); } } const mapStateToProps = (state) => ({ cars: state.cars }); const mapDispatchToProps = (dispatch) => ({ sortCar: (cars) => dispatch(sortCar(cars)), getCars: () => dispatch(getCars()) // getCars如果不需要参数,这里可以不传 }); export default connect(mapStateToProps, mapDispatchToProps)(Cars);
现在你再点击排序按钮,Redux开发者工具应该能看到状态更新,UI也会随之刷新了——核心就是修复了Reducer里的分号错误,同时去掉了冗余的组件state,让UI完全依赖Redux的状态。
内容的提问来源于stack exchange,提问作者James

