首页 > 解决方案 > 在 React 中执行 API 调用之前检查 setState 是否已运行

问题描述

我有一个带有文本字段的表单和一个接受多个文件的表单输入。OnSubmit 将文件发送到 Firebase 存储,后者会发回每个文件的 URL。然后将这些 URL 存储在表单对象的“photosURL”数组中,然后将其发布到 MongoDB。

问题是,每次我将表单对象数据发布到 Mongo 时,照片数组都是空的,尽管控制台日志显示它在我调用 post-to-Mongo 代码之前已被填充。这使我认为 post-to-Mongo 代码在使用照片 URL 填充之前使用表单对象值。

问题是,在运行代码将数据推送到 MongoDB 之前,如何检查照片数组是否已填充?我已经在使用 Promise.all 理论上等待发送所有文件并返回 URL,但我无法弄清楚为什么每次将数据发送到 Mongo 时 photoURLs 数组都是空的。

这是代码:

const [form, setForm] = useState({
    userId: '',
    post: '',
    createdAt: createdAt,
    photoURLs: [],
})

const handleSubmit = (e) => {
    e.preventDefault()
    newPost ? postData(form) : ...
}

// SEND FILE TO FIREBASE AND GET BACK THE URL
async function handleUpload(file) {

    const storageRef = useStorage.ref("PostImages");
    const fileRef = storageRef.child(`${nanoid()}`);

    return fileRef.put(file).then(() => {
        return fileRef.getDownloadURL().then(function (url) {
            photoArray.push(url);
            setForm(prevState => ({ ...prevState, photos: photoArray }))
        });
    });
}

// POST FUNCTION
const postData = async (form) => {

    setLoading(true)
    let thisFileArray = fileInput.current.files;
    const uploadTasks = [];
    for (let i = 0; i < thisFileArray.length; i++) {
        uploadTasks.push(handleUpload(thisFileArray[i]));
    }
    Promise.all(uploadTasks).then(() => {
        axios.post('/api/posts', form)
        .then(response => {
            ...
        })
        .catch(error => {
            ...
        })
    })
}

谁能看看出了什么问题?

编辑:这是表单对象的控制台日志,在 axios.post 代码之前调用(它显示填充的 photosURL):

createdAt: 1630072305502
photos: 
    0: "https://firebasestorage.googleapis.com/..."
    1: "https://firebasestorage.googleapis.com/..."
post: "sample text"
userId: "1iNGV..."

标签: reactjs

解决方案


我认为您遇到了时间问题。
不要忘记 React 状态更新是异步的,如此所述。
我建议直接传递您的 URL,而不是通过组件的状态:

async function handleUpload(file) {
    const storageRef = useStorage.ref("PostImages");
    const fileRef = storageRef.child(`${nanoid()}`);
    await fileRef.put(file);
    const url = await fileRef.getDownloadURL();
    return url; // Send back the download URL
}

const postData = async (form) => {
    setLoading(true);
    let thisFileArray = fileInput.current.files;
    const uploadTasks = [];
    for (let i = 0; i < thisFileArray.length; i++) {
        uploadTasks.push(handleUpload(thisFileArray[i]));
    }
    const photos = await Promise.all(uploadTasks); // Get all URLs here
    await axios.post('/api/posts', {...form, photos}); // Send URLs to your server
    setLoading(false);
}


推荐阅读