React Native设置初始状态触发无限重渲染报错排查
问题根源
你遇到的无限重渲染报错,是因为在组件渲染的执行流程里直接调用了状态更新方法setArticles:
每次组件渲染走到非loading、非error的分支时,就会执行setArticles(data.items),状态更新会触发组件重新渲染,重渲染时又会再次执行这段setState逻辑,形成死循环,触发React的渲染次数保护机制。
另外你单独存一份articles状态本身是冗余设计,useQuery返回的data本身就是响应式的查询结果,不需要额外拷贝到本地state里。
修复实现
推荐方案:移除冗余本地状态,用派生数据渲染
不需要额外维护articles状态,加载阶段直接返回加载/错误态组件,加载完成后基于查询结果和当前筛选条件计算要展示的文章列表即可,从根源上避免渲染阶段setState的问题:
const HomeScreen = () => { const {loading, error, data} = useQuery(queryRepository.GET_ARTICLES); const [activeCategory, setActiveCategory] = useState(null); // 直接派生展示的文章列表,不需要额外存状态 const displayArticles = useMemo(() => { if (!data?.items) return []; return activeCategory ? CategoryService.filterByCategoryName(activeCategory, data.items) : data.items; }, [data, activeCategory]); const filterByCategory = (name) => { setActiveCategory(name); }; if (loading) return <Spinner />; if (error) return <Error>{error}</Error>; return ( <View style={globalStyles.container}> <View> <View style={globalStyles.categoryMenuContainer}> <CategoryMenu filterByCategory={filterByCategory} /> </View> <View style={globalStyles.reviewsContainer}> <ArticleList articles={displayArticles} /> </View> </View> </View> ); };
备选方案:需要同步数据到本地状态时用useEffect触发更新
如果有特殊业务要求必须把查询结果存在本地state,禁止在渲染流程里直接调用setState,要放到useEffect回调中,仅在查询返回的data变化时执行同步:
const HomeScreen = () => { const {loading, error, data} = useQuery(queryRepository.GET_ARTICLES); const [articles, setArticles] = useState([]); // 监听data变化同步到本地状态,不会触发循环渲染 useEffect(() => { if (data?.items) { setArticles(data.items); } }, [data]); const filterByCategory = name => { setArticles(CategoryService.filterByCategoryName(name, data.items)); }; if (loading) return <Spinner />; if (error) return <Error>{error}</Error>; return ( <View style={globalStyles.container}> <View> <View style={globalStyles.categoryMenuContainer}> <CategoryMenu filterByCategory={filterByCategory} /> </View> <View style={globalStyles.reviewsContainer}> <ArticleList articles={articles} /> </View> </View> </View> ); };
以上两种实现都满足核心诉求:接口加载完成前不会渲染主页内容,loading状态下直接展示加载指示器,不会出现首次渲染时文章列表为空的问题。
内容的提问来源于stack exchange,提问作者jvegax
相关产品推荐
相关产品推荐

