为什么给useState传入数组后,我定义的State数组依然没有更新?
问题原因
- 异步操作时序错误:
storageRef.listAll()以及每个文件对应的getDownloadURL()都是异步Promise任务,你当前把setImagesArray写在了所有异步逻辑的外侧,属于同步执行栈的代码,会早于所有Promise的then回调执行。执行set方法的时间点,tempImagesArray还没有被推入任何url。你在控制台看到tempImagesArray有值是浏览器控制台对引用类型的延迟求值特性导致的:打印时数组实际为空,你手动点击展开控制台输出时才会读取数组的最新值,属于控制台的显示误导。 - React状态更新的异步特性:
setImagesArray是React的异步状态更新方法,调用后不会立刻修改当前渲染上下文里的imagesArray变量,需要等到下一次组件重渲染时才能拿到更新后的状态值,所以调用set之后立刻打印必然拿到旧的空数组。
修复方案
核心思路是用Promise.all等待所有图片URL的获取请求全部完成后,再统一更新状态,修复后的代码如下:
const [imagesArray, setImagesArray] = useState([]); useEffect(() => { storageRef .listAll() .then(async (res) => { // 生成所有getDownloadURL请求的Promise数组 const urlPromises = res._delegate.items.map(imageRef => projectStorage.ref(imageRef._location.path_).getDownloadURL() ); // 等待所有请求执行完成,拿到全部URL const tempImagesArray = await Promise.all(urlPromises); // 统一更新状态,用函数式更新避免闭包陷阱 setImagesArray(prevState => [...prevState, ...tempImagesArray]); // 此处可拿到获取到的全部URL console.log("Temp images arr is", tempImagesArray); }) .catch((err) => { console.log(err); }); }, []); // 组件重渲染时会打印更新后的状态,可在此验证更新结果 console.log("Main images state arr is ", imagesArray);
如果不需要保留imagesArray之前的旧值,可以直接写setImagesArray(tempImagesArray),不需要展开之前的状态。
内容的提问来源于stack exchange,提问作者K Kimash
相关产品推荐
相关产品推荐

