自定义Hook结合Redux Toolkit排序卡片失效问题求助
我正在编写自定义Hook实现卡片排序,卡片首次渲染时显示API返回的默认顺序,只有按下Ctrl+S保存触发Vite更新(强制重新渲染)后才会完成排序。刚接触自定义Hook,不清楚问题所在,怀疑是useEffect内的dispatch操作有问题,请问如何让卡片正常排序?
自定义Hook代码
import { useEffect, useState } from 'react'; // Redux import { getAllBosses, SortBosses } from '../redux/slices/Bosses'; import { useDispatch, useSelector } from 'react-redux'; export default function useFetch(value) { const dispatch = useDispatch(); const { list: bosses } = useSelector(state => state.bosses); const [type, setType] = useState([]); useEffect(() => { value === 'default' ? dispatch(getAllBosses()) : dispatch(SortBosses(value)); setType(bosses); }, [value]); return type; }
组件代码
import { useEffect, useState } from 'react'; // Redux // import { getAllBosses } from '../../redux/slices/Bosses'; // import { useDispatch, useSelector } from 'react-redux'; // components import { BossCard, Loading, Pagination, Error } from '@components'; import { useFetch } from '../../hooks'; import { Cards } from '@components/styles/Cards.style'; function BossesList() { // const dispatch = useDispatch(); const bosses = useFetch('ztoa'); const [currentPage, setCurrentPage] = useState(1); const bossPerPage = 8; const indexOfLastBoss = currentPage * bossPerPage; const indexOfFirstBoss = indexOfLastBoss - bossPerPage; const currentBosses = bosses.slice(indexOfFirstBoss, indexOfLastBoss); const pages = pageNumber => { setCurrentPage(pageNumber); }; // useEffect(() => { // dispatch(getAllBosses()); // }, [dispatch]); useEffect(() => { setCurrentPage(1); }, [bosses]); return ( <> <Cards> {currentBosses.length !== 0 ? ( currentBosses.map((boss, index) => boss.error ? ( <Error key={index} error={'No boss with that name.'} /> ) : ( <BossCard key={boss.id} id={boss.id} name={boss.name} image={boss.image} /> ) ) ) : ( <div> <Loading /> </div> )} </Cards> <Pagination bossPerPage={bossPerPage} bosses={bosses.length} currentBosses={currentBosses} pages={pages} currentPage={currentPage} /> </> ); } export default BossesList;
问题原因
核心问题是Redux的状态更新是异步的:你在useEffect里调用dispatch(SortBosses(value))后,立刻执行setType(bosses),这时候Redux还没完成状态更新,bosses还是初始的默认数据,所以type拿到的不是排序后的结果。只有当组件强制重新渲染时,useSelector才会读取到Redux里更新后的排序数据,type才会同步。
另外,你在Hook里维护的type state完全是多余的——useSelector会自动监听Redux状态变化,一旦状态更新就会触发组件重新渲染,直接返回bosses就行。
修复方案
1. 修改自定义Hook
去掉多余的type state,直接返回useSelector获取的bosses,同时完善useEffect的依赖项:
import { useEffect } from 'react'; // Redux import { getAllBosses, SortBosses } from '../redux/slices/Bosses'; import { useDispatch, useSelector } from 'react-redux'; export default function useFetch(value) { const dispatch = useDispatch(); const { list: bosses } = useSelector(state => state.bosses); useEffect(() => { // 触发对应的数据获取/排序操作 if (value === 'default') { dispatch(getAllBosses()); } else { dispatch(SortBosses(value)); } }, [dispatch, value]); // 加上dispatch和value作为依赖 return bosses; }
2. 调整组件逻辑
因为现在bosses直接来自Redux,状态更新会自动触发重新渲染,原来的分页重置逻辑可以保留,但注意如果bosses是数组,依赖项会在数组引用变化时触发,这符合需求:
// ... 其他代码不变 useEffect(() => { setCurrentPage(1); }, [bosses]); // ... 其他代码不变
这样修改后,当组件首次渲染时,useEffect会触发SortBosses('ztoa'),Redux状态更新后,useSelector会立刻拿到排序后的bosses,组件会重新渲染并显示排序后的卡片,无需等待强制刷新。
内容的提问来源于stack exchange,提问作者Dumbasswithaname

