Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript承诺+;useState+;火箭筒_Javascript_Reactjs_React Native_Google Cloud Firestore_Es6 Promise - Fatal编程技术网

Javascript承诺+;useState+;火箭筒

Javascript承诺+;useState+;火箭筒,javascript,reactjs,react-native,google-cloud-firestore,es6-promise,Javascript,Reactjs,React Native,Google Cloud Firestore,Es6 Promise,我的代码中有一个数据库侦听器,我试图获取每个用户的新帖子,然后(当我将所有帖子都放在一个数组中时)更新帖子状态 我的代码看起来像这样,但工作不好,因为setPosts是异步的,有时在结束状态更新之前可能会再次调用它。我认为我需要用承诺来包装侦听器,但我不知道如何在组件卸载时分离侦听器 useEffect(() => { const { firebase } = props; // Realtime database listener const unsuscrib

我的代码中有一个数据库侦听器,我试图获取每个用户的新帖子,然后(当我将所有帖子都放在一个数组中时)更新帖子状态

我的代码看起来像这样,但工作不好,因为setPosts是异步的,有时在结束状态更新之前可能会再次调用它。我认为我需要用承诺来包装侦听器,但我不知道如何在组件卸载时分离侦听器

useEffect(() => {
    const { firebase } = props;

    // Realtime database listener
    const unsuscribe = firebase
      .getDatabase()
      .collection("posts")
      .doc(firebase.getCurrentUser().uid)
      .collection("userPosts")
      .onSnapshot((snapshot) => {
        let changes = snapshot.docChanges();
        changes.forEach(async (change) => {
          if (change.type === "added") {
            // Get the new post
            const newPost = change.doc.data();

            // TODO - Move to flatlist On end reached
            const uri = await firebase
              .getStorage()
              .ref(`photos/${newPost.id}`)
              .getDownloadURL();

            // TODO - Add the new post *(sorted by time)* to the posts list
            setPosts([{ ...newPost, uri }, ...posts]);
          }
        });
      });

    /* Pd: At the first time, this function will get all the user's posts */

    return () => {
      // Detach the listening agent
      unsuscribe();
    };
  }, []);
有什么想法吗

此外,我还想做:

useEffect(() => {

const { firebase } = props;

let postsArray = [];

// Realtime database listener
const unsuscribe = firebase
  .getDatabase()
  .collection("posts")
  .doc(firebase.getCurrentUser().uid)
  .collection("userPosts")
  .orderBy("time") // Sorted by date
  .onSnapshot((snapshot) => {
    let changes = snapshot.docChanges();
    changes.forEach(async (change) => {
      if (change.type === "added") {
        // Get the new post
        const newPost = change.doc.data();

        // Add the new post to the posts list
        postsArray.push(newPost);
      }
    });

    setPosts(postsArray.reverse());
  });
但是在本例中,post uri也保存在firestore文档中(我可以这样做,因为我在firestore上使用了一个从存储中获取post的云函数),我不知道这是否是一个好的做法

谢谢

更新 云功能代码:

exports.validateImageDimensions = functions
  .region("us-central1")
  .runWith({ memory: "2GB", timeoutSeconds: 120 })
  .https.onCall(async (data, context) => {
    // Libraries
    const admin = require("firebase-admin");
    const sizeOf = require("image-size");
    const url = require("url");
    const https = require("https");
    const sharp = require("sharp");
    const path = require("path");
    const os = require("os");
    const fs = require("fs");

    // Lazy initialization of the Admin SDK
    if (!is_validateImageDimensions_initialized) {
      const serviceAccount = require("./serviceAccountKey.json");
      admin.initializeApp({
        // ...
      });

      is_validateImageDimensions_initialized = true;
    }

    // Create Storage
    const storage = admin.storage();

    // Create Firestore
    const firestore = admin.firestore();

    // Get the image's owner
    const owner = context.auth.token.uid;

    // Get the image's info
    const { id, description, location, tags } = data;

    // Photos's bucket
    const bucket = storage.bucket("bucket-name");

    // File Path
    const filePath = `photos/${id}`;

    // Get the file
    const file = getFile(filePath);

    // Check if the file is a jpeg image
    const metadata = await file.getMetadata();
    const isJpgImage = metadata[0].contentType === "image/jpeg";

    // Get the file's url
    const fileUrl = await getUrl(file);

    // Get the photo dimensions using the `image-size` library
    getImageFromUrl(fileUrl)
      .then(async (image) => {
        // Check if the image has valid dimensions
        let dimensions = sizeOf(image);
        // Create the associated Firestore's document to the valid images
        if (isJpgImage && hasValidDimensions(dimensions)) {
          // Create a thumbnail for the uploaded image
          const thumbnailPath = await generateThumbnail(filePath);

          // Get the thumbnail
          const thumbnail = getFile(thumbnailPath);

          // Get the thumbnail's url
          const thumbnailUrl = await getUrl(thumbnail);

          try {
            await firestore
              .collection("posts")
              .doc(owner)
              .collection("userPosts")
              .add({
                id,
                uri: fileUrl,
                thumbnailUri: thumbnailUrl, // Useful for progress images
                description,
                location,
                tags,
                date: admin.firestore.FieldValue.serverTimestamp(),
                likes: [], // At the first time, when a post is created, zero users has liked it
                comments: [], // Also, there aren't any comments
                width: dimensions.width,
                height: dimensions.height,
              });

            // TODO: Analytics posts counter
          } catch (err) {
            console.error(
              `Error creating the document in 'posts/{owner}/userPosts/' where 'id === ${id}': ${err}`
            );
          }
        } else {
          // Remove the files that are not jpeg images, or whose dimensions are not valid
          try {
            await file.delete();

            console.log(
              `The image '${id}' has been deleted because it has invalid dimensions.
               This may be an attempt to break the security of the app made by the user '${owner}'`
            );
          } catch (err) {
            console.error(`Error deleting invalid file '${id}': ${err}`);
          }
        }
      })
      .catch((e) => {
        console.log(e);
      });

    /* ---------------- AUXILIAR FUNCTIONS  ---------------- */

    function getFile(filePath) {
      /* Get a file from the storage bucket */

      return bucket.file(filePath);
    }

    async function getUrl(file) {
      /* Get the public url of a file  */

      const signedUrls = await file.getSignedUrl({
        action: "read",
        expires: "01-01-2100",
      });

      // signedUrls[0] contains the file's public URL
      return signedUrls[0];
    }

    function getImageFromUrl(uri) {
      return new Promise((resolve, reject) => {
        const options = url.parse(uri); // Automatically converted to an ordinary options object.
        const request = https.request(options, (response) => {
          if (response.statusCode < 200 || response.statusCode >= 300) {
            return reject(new Error("statusCode=" + response.statusCode));
          }
          let chunks = [];
          response.on("data", (chunk) => {
            chunks.push(chunk);
          });
          response.on("end", () => {
            try {
              chunks = Buffer.concat(chunks);
            } catch (e) {
              reject(e);
            }
            resolve(chunks);
          });
        });

        request.on("error", (e) => {
          reject(e.message);
        });
        // Send the request
        request.end();
      });
    }

    function hasValidDimensions(dimensions) {
      // Posts' valid dimensions
      const validDimensions = [
        {
          width: 1080,
          height: 1080,
        },
        {
          width: 1080,
          height: 1350,
        },
        {
          width: 1080,
          height: 750,
        },
      ];

      return (
        validDimensions.find(
          ({ width, height }) =>
            width === dimensions.width && height === dimensions.height
        ) !== undefined
      );
    }

    async function generateThumbnail(filePath) {
      /* Generate thumbnail for the progressive images */

      // Download file from bucket
      const fileName = filePath.split("/").pop();
      const tempFilePath = path.join(os.tmpdir(), fileName);

      const thumbnailPath = await bucket
        .file(filePath)
        .download({
          destination: tempFilePath,
        })
        .then(() => {
          // Generate a thumbnail using Sharp
          const size = 50;
          const newFileName = `${fileName}_${size}_thumb.jpg`;
          const newFilePath = `thumbnails/${newFileName}`;
          const newFileTemp = path.join(os.tmpdir(), newFileName);
          sharp(tempFilePath)
            .resize(size, null)
            .toFile(newFileTemp, async (_err, info) => {
              // Uploading the thumbnail.
              await bucket.upload(newFileTemp, {
                destination: newFilePath,
              });

              // Once the thumbnail has been uploaded delete the temporal file to free up disk space.
              fs.unlinkSync(tempFilePath);
            });

          // Return the thumbnail's path
          return newFilePath;
        });

      return thumbnailPath;
    }
  });
exports.validateImageDimensions=函数
.地区(“美国中部1”)
.runWith({内存:“2GB”,超时秒:120})
.https.onCall(异步(数据、上下文)=>{
//图书馆
const admin=require(“firebase管理员”);
const sizeOf=require(“图像大小”);
const url=require(“url”);
const https=require(“https”);
常量夏普=要求(“夏普”);
常量路径=要求(“路径”);
常数os=要求(“os”);
常数fs=要求(“fs”);
//ADMINSDK的延迟初始化
如果(!是否已初始化validateImageDimensions){
const servicecomport=require(“./servicecomportkey.json”);
admin.initializeApp({
// ...
});
is\u validateImageDimensions\u initialized=true;
}
//创建存储
const storage=admin.storage();
//创建Firestore
const firestore=admin.firestore();
//获取图像的所有者
const owner=context.auth.token.uid;
//获取图像的信息
const{id,description,location,tags}=数据;
//照片的水桶
const bucket=storage.bucket(“bucket name”);
//文件路径
const filePath=`photos/${id}`;
//获取文件
const file=getFile(filePath);
//检查文件是否为jpeg图像
const metadata=wait file.getMetadata();
const isJpgImage=元数据[0]。contentType==“image/jpeg”;
//获取文件的url
const fileUrl=wait getUrl(文件);
//使用“图像大小”库获取照片尺寸
getImageFromUrl(文件URL)
。然后(异步(图像)=>{
//检查图像是否具有有效的尺寸
让尺寸=sizeOf(图像);
//创建与有效图像关联的Firestore文档
if(isJpgImage和hasValidDimensions(尺寸)){
//为上传的图像创建缩略图
const thumbnailPath=等待生成缩略图(filePath);
//获取缩略图
const thumbnail=getFile(thumbnailPath);
//获取缩略图的url
const thumbnailUrl=wait getUrl(缩略图);
试一试{
等待火库
.收集(“员额”)
.doc(所有者)
.collection(“用户帖子”)
.添加({
身份证件
uri:fileUrl,
thumbnailUri:thumbnailUrl,//对进度图像有用
描述
位置,
标签,
日期:admin.firestore.FieldValue.serverTimestamp(),
喜欢:[],//第一次创建帖子时,没有用户喜欢它
注释:[],//另外,没有任何注释
宽度:尺寸。宽度,
高度:尺寸。高度,
});
//TODO:分析帖子计数器
}捕捉(错误){
控制台错误(
`在'posts/{owner}/userPosts/'中创建文档时出错,其中'id===${id}':${err}`
);
}
}否则{
//删除非jpeg图像或尺寸无效的文件
试一试{
等待文件。删除();
console.log(
`映像“${id}”已被删除,因为它的维度无效。
这可能是试图破坏由用户“${owner}”创建的应用程序的安全性`
);
}捕捉(错误){
错误(`error删除无效文件'${id}':${err}`);
}
}
})
.catch((e)=>{
控制台日志(e);
});
/*------------辅助功能------------------*/
函数getFile(文件路径){
/*从存储桶中获取文件*/
返回bucket.file(filePath);
}
异步函数getUrl(文件){
/*获取文件的公共url*/
const signedUrls=await file.getSignedUrl({
行动:“阅读”,
到期日期:“01-01-2100”,
});
//signedUrls[0]包含文件的公共URL
返回签名URL[0];
}
函数getImageFromUrl(uri){
返回新承诺((解决、拒绝)=>{
const options=url.parse(uri);//自动转换为普通选项对象。
const request=https.request(选项,(响应)=>{
如果(response.statusCode<200 | | response.statusCode>=300){
返回拒绝(新错误(“statusCode=“+response.statusCode”);
}
让chunks=[];
响应.on(“数据”,(块)=>{
推(chunk);
});
响应。在(“结束”、()=>{
试一试{
chunks=Buffer.concat(chunks);
}捕获(e){
拒绝(e);
}
分解(块);
});
});
请求.on(“错误”,(e)=>{
拒绝(e.message);
});
//发送请求
request.end();
});
}
函数hasValidDimensions(尺寸){
//帖子的有效维度
常数有效尺寸=[
{
宽度:1080,
身高:1080,
},
{
宽度:1080,
身高:1350,