点击歌曲项获数据后,如何用React Hooks实现页面跳转?
问题:点击歌曲列表项后无法在数据返回时触发页面跳转
问题场景
点击歌曲列表项时,需通过歌曲ID获取该歌曲的路径等元数据,随后跳转到对应歌曲页面。当前使用useEffect监听状态变化实现,但无法在数据返回后正确触发跳转,且需要通过results.length > 0校验API异常情况。
当前代码的问题根源
handleClick定义在useEffect内部,点击触发时,dispatch(SongActions.searchSong(myId))是异步操作,此时results尚未更新,跳转判断逻辑直接跳过;- 当异步请求完成、
results更新后,useEffect重新执行并创建新的handleClick,但点击事件已绑定旧的handleClick,更新后的results无法触发跳转。
正确实现方案
方案一:拆分点击逻辑与跳转逻辑(推荐)
将点击触发请求和监听状态跳转拆分为两个独立逻辑,符合React状态管理的常规模式:
// 点击事件处理:仅触发数据请求 const handleClick = (myId: string) => { dispatch(SongActions.searchSong(myId)); }; // 单独监听results变化,满足条件时执行跳转 useEffect(() => { if (results.length > 0 && Object.keys(results[0]).length > 0) { navigate(`/songs/${results[0].myPath}`); // 可选:跳转后清空results,避免组件重新渲染时自动跳转 // dispatch({ type: SearchActionType.CLEAR_RESULTS }); } }, [results, navigate]);
点击事件保持原有写法:
<Typography onClick={() => handleClick(songItem.songId)} sx={styles.songListItemText}>{songItem.Title}</Typography>
方案二:通过回调函数处理跳转(可选)
如果不需要依赖全局results状态,可以在调用action时传入回调,请求完成后直接执行跳转:
修改action实现
searchSong: (obj: SearchSongInputModel, onSuccess?: (data: any[]) => void): AppThunk<SearchPayload> => async (dispatch) => { dispatch({ payload: { isLoading: true }, type: SearchActionType.REQUEST, }); try { const response = await SearchApi.searchSongAsync(obj); if (response.length === 0) { toast.info(`No data found: ${obj.SongId}`); } else { // 请求成功且有数据时执行回调 onSuccess?.(response); } dispatch({ type: SearchActionType.RECEIVED_SONG, payload: { results: response }, }); } catch (e) { console.error("Error: ", e); } }
组件中调用
const handleClick = (myId: string) => { dispatch(SongActions.searchSong(myId, (response) => { if (response.length > 0 && Object.keys(response[0]).length > 0) { navigate(`/songs/${response[0].myPath}`); } })); };
方案对比
- 方案一:适合需要全局共享
results数据的场景,通过监听状态变化触发副作用,逻辑清晰; - 方案二:更直接,避免其他地方更新
results时意外触发跳转,适合仅在点击场景下处理跳转的需求。
内容的提问来源于stack exchange,提问作者Sachihiro
相关产品推荐
相关产品推荐

