Expo Camera拍摄照片后URI无法同步更新至State的问题
嗨,我完全懂你现在的困惑——明明调用setPhoto(data.uri)之后页面能正常显示拍摄的照片,但紧接着打印photo却还是null,这看起来有点矛盾对吧?其实这是React状态更新的异步特性在搞鬼,不是你的代码出问题啦。
问题根源:React状态更新是异步的
React的useState更新函数(也就是你用的setPhoto)是异步批量执行的。当你调用setPhoto(data.uri)时,React不会立刻修改photo变量的值,而是把这个更新请求加入到一个任务队列里,等当前函数(也就是takePic)的所有代码执行完毕后,才会去处理队列里的更新操作,然后重新渲染组件。所以在setPhoto之后马上打印photo,你拿到的还是更新前的旧值——也就是初始的null。
而页面能正确显示图片,是因为状态更新完成后组件会重新渲染,这时候photo已经是新的URI了,所以if(photo)的判断能生效,渲染出图片组件。
解决办法
1. 用useEffect监听状态变化(适合需要在状态更新后执行操作的场景)
如果需要在photo更新后做一些后续操作(比如打印日志、保存到相册),可以用useEffect监听photo的变化,当photo的值改变时,这个副作用就会触发:
import React, { useEffect, useState, useRef } from "react"; // 其他import... export default function Scan() { let cameraRef = useRef(null); const [hasCameraPermission, setCameraPermission] = useState(); const [hasMediaPermission, setMediaPermission] = useState(); const [photo, setPhoto] = useState(null); // 新增这个useEffect监听photo变化 useEffect(() => { if (photo) { console.log("更新后的photo URI:", photo); // 这里可以添加保存到相册等操作 // await MediaLibrary.saveToLibraryAsync(photo); } }, [photo]); // 依赖数组传入photo,只有photo变化时才执行 // 其他代码... const takePic = async () => { if (cameraRef) { try { const data = await cameraRef.current.takePictureAsync(); setPhoto(data.uri); console.log("拍摄得到的URI:", data.uri); // 直接用data.uri是实时的 } catch (e) { console.log(e); } } }; // 其他代码... }
2. 直接使用data.uri(适合在takePic函数内需要用到URI的场景)
如果只是在拍摄照片后立刻需要用到这个URI,完全不需要等状态更新,直接用data.uri就可以了——因为你已经从takePictureAsync的返回值里拿到了最新的URI:
const takePic = async () => { if (cameraRef) { try { const data = await cameraRef.current.takePictureAsync(); setPhoto(data.uri); console.log("拍摄得到的URI:", data.uri); // 比如要保存到相册,直接用data.uri就行 if (hasMediaPermission) { await MediaLibrary.saveToLibraryAsync(data.uri); } } catch (e) { console.log(e); } } };
关于你尝试用useRef的问题
你提到用useRef存photo但没生效,这是因为useRef的.current值变化不会触发组件重新渲染。虽然你可以把URI存在ref里,但页面不会自动更新显示新的图片,所以对于需要驱动UI变化的状态,还是得用useState来管理哦。
备注:内容来源于stack exchange,提问作者Nipun Avishka De Zoysa

