React+Redux+Hooks项目调用搜索API后渲染结果为undefined如何修复
问题根因梳理
- 搜索结果和全量电影共用了同一个Redux状态字段,且数据结构不匹配
你代码里movies和searchResults都从state.shows取值,而全量电影接口返回的是[{id:xxx, ...}]的扁平结构,搜索接口返回的是[{show: {id:xxx, ...}}]的嵌套结构,两类数据结构不一致,用同一字段存储必然会在遍历的时候取不到对应属性。
- 搜索结果和全量电影共用了同一个Redux状态字段,且数据结构不匹配
- 异步搜索请求和状态切换时序错误
调用dispatch(searchMovieByTitle(searchString))后立刻执行setIsFromSearchResults(true),而Redux thunk的异步请求还未返回,搜索结果还未更新到状态中,此时渲染搜索列表用的还是旧的state.shows数据,自然取不到result.show。
- 异步搜索请求和状态切换时序错误
- 搜索action里存在无意义的异步处理逻辑
response.data本身就是同步返回的数组,不需要用map包装再走Promise.all,属于冗余逻辑。
- 搜索action里存在无意义的异步处理逻辑
具体修复步骤
第一步:修改Redux Reducer,拆分存储两类数据
你的reducer需要拆分两个字段分别存全量电影和搜索结果,示例如下:
// 你的shows reducer文件 import { FETCH_ALL_SHOWS, SEARCH_MOVIE_BY_TITLE } from '../actions/types'; const initialState = { shows: [], // 存全量电影 searchResults: [] // 单独存搜索结果 } export default function showsReducer(state = initialState, action) { switch(action.type) { case FETCH_ALL_SHOWS: return { ...state, shows: action.payload } case SEARCH_MOVIE_BY_TITLE: return { ...state, searchResults: action.payload } default: return state } }
第二步:修改组件内useSelector的取值逻辑
// 原来的错误写法 // const movies = useSelector((state: RootStateOrAny) => state.shows) // const searchResults = useSelector((state: RootStateOrAny) => state.shows); // 修改后 const movies = useSelector((state: RootStateOrAny) => state.shows.shows) const searchResults = useSelector((state: RootStateOrAny) => state.shows.searchResults);
第三步:修复异步状态切换的时序问题
不要在调用搜索dispatch后立刻切换到搜索结果状态,调整逻辑保证搜索请求完成后再切换状态:
// 1. 先修改搜索action,去掉冗余逻辑,支持promise链式调用 export const searchMovieByTitle = (title: string) => async (dispatch: any) => { try { let response = await ShowsService.searchMovieByTitle(title); dispatch({type: SEARCH_MOVIE_BY_TITLE, payload: response.data}); } catch (err) { console.log(err); } } // 2. 修改组件内的搜索触发逻辑 const findMovieByTitle = () => { setLoading(true); // 等待异步请求完成后再切换搜索状态 dispatch(searchMovieByTitle(searchString)).then(() => { setIsFromSearchResults(true); setSearchString(''); setLoading(false); }); }
第四步:可选修复分页逻辑
你当前的分页逻辑只会返回最后一页的数据,如果要保留第一页25条的逻辑,直接简化为:
const paginatedArr = movies.slice(0, 25);
如果要做多页切换,额外加currentPage状态配合计算分页区间即可。
可选优化:加空值判断避免报错
遍历搜索结果前加可选链判断,避免数组为空时报错:
{searchResults?.map((result: any, index: number) => { // 原有渲染逻辑 })}
内容的提问来源于stack exchange,提问作者Nzadibe
相关产品推荐
相关产品推荐

