React18中Invalid hook call错误及组件不重渲染问题求助
问题分析与解决方案
错误根源
你在MapStateToProps这个普通函数中调用了useParams(),违反了React Hook的核心规则:Hook只能在函数组件的顶层代码或自定义Hook内部调用,普通辅助函数里不能使用Hook,这就是控制台抛出Invalid hook call错误的原因。
同时,因为MapStateToProps无法正确获取到路由ID,导致返回的expense数据始终无法和redux状态同步,这也是编辑后组件不重渲染的直接原因。
解决方案
方案1:改用React-Redux Hook写法(推荐,适配React18+)
直接使用useSelector和useDispatch替代传统的connect,在组件内直接获取路由参数与redux状态,代码更简洁直观:
import { useSelector, useDispatch } from "react-redux"; import { useParams } from "react-router-dom"; import ExpenseForm from "./ExpenseForm"; import { editExpense, removeExpense } from '../actions/expenses'; import { useNavigate } from 'react-router-dom'; function EditExpensePage (){ const { id } = useParams(); const navigate = useNavigate(); // 从redux状态中筛选当前ID对应的费用项 const expense = useSelector(state => state.expenses.find(exp => exp.id === id)); const dispatch = useDispatch(); return( <div> <ExpenseForm expense={expense} onSubmit={(expense) =>{ dispatch(editExpense(id, expense)); navigate('/'); }} /> <button onClick={()=>{ dispatch(removeExpense({id: expense.id})); navigate('/'); }}>Remove</button> </div> ); }; export default EditExpensePage;
方案2:修复传统connect写法
如果需要保留connect的使用方式,需要将路由ID从组件传递给MapStateToProps(它可以接收第二个参数ownProps,即组件的props):
import { connect } from "react-redux"; import { useParams } from "react-router-dom"; import ExpenseForm from "./ExpenseForm"; import { editExpense, removeExpense } from '../actions/expenses'; import { useNavigate } from 'react-router-dom'; function EditExpensePage (props){ const { id } = useParams(); const navigate = useNavigate(); return( <div> <ExpenseForm expense={props.expense} onSubmit={(expense) =>{ props.dispatch(editExpense(id, expense)); navigate('/'); }} /> <button onClick={()=>{ props.dispatch(removeExpense({id: props.expense.id})); navigate('/'); }}>Remove</button> </div> ); }; // 通过ownProps接收组件传递的ID,筛选对应费用项 function MapStateToProps(state, ownProps) { return{ expense: state.expenses.find((expense) => expense.id === ownProps.id) }; }; // 包装组件,将路由ID作为props传递给MapStateToProps export default connect(MapStateToProps)((props) => { const { id } = useParams(); return <EditExpensePage {...props} id={id} />; });
效果说明
修复后,当你执行编辑操作时,redux状态会更新,组件会自动感知到状态变化并重新渲染,展示修改后的费用数据。
内容的提问来源于stack exchange,提问作者chidijoe
相关产品推荐
相关产品推荐

