React组件中Promise结果存入数组后渲染为空,如何不异步化组件解决?
问题:异步请求获取数据后数组为空,无法渲染书籍列表
以下是我编写的React组件代码,调用异步函数获取指定分类的书籍:
function Bookshelf(props) { const { genre } = props; const books = []; const arrayOfPromises = []; arrayOfPromises.push(getBooksUnderGenre(genre)) // 这是异步函数 Promise.all(arrayOfPromises) .then(results => { console.log(results); const result = results[0]; books.push(result); }); books.map((book, i) => { return ( <Text> {book.name} </Text> ) }); };
执行console.log(results)时终端能正常输出所需结果,但const books = []始终是空数组,导致map操作在空数组上执行,没有渲染任何内容。想问下能不能在不把Bookshelf组件改成异步函数的前提下解决这个问题?如果不行的话,正确的做法是什么?
附results的输出内容:
[ [ { genre: "fantasy", id: "19", type: "book", name: "Star Night", }, { genre: "fantasy", id: "20", type: "book", name: "A Moon Far Away", }, { genre: "fantasy", id: "21", type: "book", name: "Green Lands", }, ], ];
解决方案
首先明确:React组件不能是异步函数,因为React要求组件返回JSX元素,而异步函数返回的是Promise,React无法识别,所以不存在把组件改成异步的说法。你的核心问题有两个:
- 异步操作滞后于组件渲染,当执行
books.map时,Promise还未完成,books还是初始的空数组 - 直接修改普通数组
books不会触发React组件的重新渲染,就算后续异步请求完成、数组内容更新了,组件也不会重新读取新内容
正确的解决方式是用React的状态管理和副作用处理:
修改后的代码
import { useState, useEffect } from 'react'; function Bookshelf(props) { const { genre } = props; // 用useState保存书籍状态,初始为空数组 const [books, setBooks] = useState([]); // 用useEffect处理异步请求,依赖genre,当genre变化时重新请求 useEffect(() => { // 定义异步函数处理请求 const fetchBooks = async () => { try { const results = await Promise.all([getBooksUnderGenre(genre)]); // results是数组的数组,取出里面的书籍列表 const bookList = results[0]; // 更新状态,触发组件重新渲染 setBooks(bookList); } catch (err) { // 处理请求错误 console.error('获取书籍失败:', err); } }; fetchBooks(); }, [genre]); // 依赖项:genre变化时重新执行 // 渲染书籍列表,空数组时显示加载提示 return ( <> {books.length === 0 ? ( <Text>加载中...</Text> ) : ( books.map((book) => ( <Text key={book.id}> {book.name} </Text> )) )} </> ); };
关键说明
- useState:用来保存书籍数据,状态更新时会自动触发组件重新渲染,异步请求完成后更新状态,组件就能拿到最新的书籍列表并渲染
- useEffect:专门处理组件的副作用(比如异步请求),第二个参数是依赖数组,只有当
genre变化时才会重新发起请求,避免不必要的重复请求 - 异步处理:用
async/await替代then写法,代码更清晰;同时加上错误捕获,避免请求失败导致的问题 - key属性:map渲染列表时必须加唯一的key,这里用书籍的
id,符合React的性能优化要求
内容的提问来源于stack exchange,提问作者nalabof679
相关产品推荐
相关产品推荐

