Как получить доступ к значениям Обещания? - PullRequest
1 голос
/ 02 ноября 2019

Я пишу систему комментариев, построенную из двух баз данных: одна содержит текст и идентификатор комментатора, который затем используется для доступа ко второй базе данных для извлечения и динамического отображения информации о профиле автора (pfp и отображаемое имя)за каждый комментарий, который они представили.

Функция внутри хука useEffect() возвращает массив Promises. Я пытался выяснить способы доступа к значениям внутри этих Обещаний, но пока безрезультатно. Я знаю, что .then() существует специально для этой цели, но я не понимаю, как и где его правильно применять в этом случае.

import React, { useEffect, useState, Fragment } from 'react'
import firebase from './firebase'

export const Comments = () => {

    const [cred, setCred] = useState('')
    const [comment, setComment] = useState('')
    const [allComments, setAllComments] = useState(null)

    useEffect(() => {

// grab the database containing poster ID 
// & text of each single comment by it's name and then map over it

        firebase.getData('text&ID').onSnapshot(snapshot => setAllComments([...snapshot.docs.map(async (doc) => {

// using the poster ID, 
// access the 'users' DB that contains the avatar & name fields

            let comment = doc.data().content
            let poster = await firebase.getData('users').doc(doc.data().posterID).get()
            let name = poster.data().name
            let avatar = poster.data().avatar

// returning an object of all the data we want to display for each comment

            return ({
                name: name,
                avatar: avatar,
                comment: comment
            })
        })]))

// if user exists, set state to their credentials

        firebase.isInitialized().then(val => setCred(val))       
    }, [])

    return allComments && <Fragment>

// submit the comment to the text&DB collection with text, poster ID and text 

        {cred && <form onSubmit={(e) => {
            e.preventDefault()
            firebase.addComment('text&ID', cred.uid, comment).then(console.log('comment sent!')).then(setComment(''))
        }}>
            <input
                type="text"
                value={comment}
                name="text"
                placeholder="comment..."
                onChange={e => { setComment(e.target.value) }}
                required
            />
            <br />
            <button >Post</button>
        </form>}
        <ul>

// the plan was to map over allComments 
// and return an <li> with all the display info
// but logging to console displays THE array of Promises
// that I want to access

            {console.log(allComments)}
        </ul>
    </Fragment>
}

Любые и все входные данные приветствуются.

Вот вывод console.log:

[Promise]
   0: Promise
      __proto__: Promise
         [[PromiseStatus]]: "resolved"
         [[PromiseValue]]: Object
            avatar: "https://i.imgur.com/v4ImnVE.jpg"
            comment: "no halo"
            name: "polnareff"
         __proto__: Object
      length: 1
      __proto__: Array(0)

Ответы [ 2 ]

0 голосов
/ 02 ноября 2019

асинхронная функция представляет asynchronous function и фактически возвращает Promise, чтобы получить уведомление, когда весь код внутри функции был выполнен.

Так что в вашем коде [...snapshot.docs.map(async ...)] вернет массив Promise. Кстати, вам не нужно использовать оператор деструктуризации ..., вы можете напрямую использовать snapshot.docs.map, который вернет новый массив.

Вы можете использовать Promise.all дождаться разрешения всех обещаний, а затем обновить переменную состояния allComments.

Вот код вашего эффекта:

useEffect(() => {

  firebase.getData('text&ID').onSnapshot(snapshot => {
    const commentPromises = snapshot.docs.map(async (doc) => {
      const {posterId} = doc.data();
      const poster = await firebase.getData('users').doc(posterID).get();
      const {avatar, name, content: comment} = poster.data()

      return {name, avatar, comment};
    });

    Promise.all(commentPromises)
      .then(setAllComments)
      .catch(...);
  });

  firebase.isInitialized()
    .then(val => setCred(val))
    .catch(...);
});
0 голосов
/ 02 ноября 2019

Перенесено из комментариев, чтобы ответить, поскольку это доказало, что ответило на вопрос.

Я предлагаю взглянуть на обещание .all ()

Это в основном принимает массив обещаний.

Promise.all([Promise1, Promise2, Promise3]) .then(result) => { console.log(result) }) .catch(error => console.log(Error in promises ${error}))

это может быть то, что вы ищете.

Если это дает правильный вывод, просто замените файл console.log на result.map(item => {<li>{item.comment}</li>}) и т. Д.

...