React Native组件首次渲染调用REST API的最佳实践
React Native TodoList首次加载API数据避免无限循环的最佳实践
核心问题原因
当使用无依赖数组的useEffect触发fetchList时,fetchList会更新Redux中state.list的数据,组件通过useSelector订阅了state.list会引发重渲染。若useEffect依赖配置不当,会触发重复执行,最终形成无限循环。
最佳实践方案
方案1:利用稳定的dispatch引用+规范依赖配置
Redux的useDispatch返回的dispatch函数引用是全局稳定的,不会随组件重新渲染而改变。将其加入useEffect的依赖数组,既能符合React Hooks规则,又能保证effect仅在组件挂载时执行一次:
import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchList } from './your-thunk-path'; function TodoList(): JSX.Element { const state: State = useSelector((state: any) => state.list); const dispatch = useDispatch(); useEffect(() => { dispatch(fetchList); }, [dispatch]); // dispatch引用稳定,不会触发重复执行 return ( <View> {/* 列表渲染逻辑 */} </View> ); }
方案2:结合请求状态判断(更健壮)
在Redux状态中维护请求状态(如Idle/Fetching/Succeeded),仅在状态为Idle时发起请求,既能避免无限循环,还能防止重复请求:
- 组件中增加状态判断:
function TodoList(): JSX.Element { const { fetchState } = useSelector((state: any) => state.list); const dispatch = useDispatch(); useEffect(() => { if (fetchState === FetchState.Idle) { dispatch(fetchList); } }, [dispatch, fetchState]); return ( <View> {/* 根据fetchState渲染加载/列表/错误状态 */} </View> ); }
- 在thunk中增加双重校验:
export const fetchList = () => (dispatch: any, getState: any) => { const { fetchState } = getState().list; // 若当前正在请求或已完成,直接返回 if (fetchState !== FetchState.Idle) return; dispatch(setListFetchState(FetchState.Fetching)); fetch(`http://{HOST}/item`) .then(response => response.json()) .then((result) => { dispatch(setListData(result)); dispatch(setListFetchState(FetchState.Succeeded)); }) .catch(() => { dispatch(setListFetchState(FetchState.Failed)); }); };
关键说明
- 不要使用完全空的依赖数组(
[]),虽然表面上能执行一次,但会触发React Hooks的lint警告,且在严格模式下可能出现重复执行的情况。 - 结合请求状态的方案更适合生产环境,能应对组件重新挂载、重复触发请求等边界场景。
内容的提问来源于stack exchange,提问作者sak
相关产品推荐
相关产品推荐

