Заполнение метода рендеринга отдельным методом в ReactJS - PullRequest
2 голосов
/ 11 февраля 2020

хорошо, так что все знают, что отдельное отображение выполнит хитрость рендеринга компонента в методе рендеринга React, что-то вроде этого:

var listOfService = ['A', 'B', 'C', 'D', 'E'];
const listItems = listOfService.map((singleItem) =>
    <a className="style_class">{singleItem}</a>
);

и если вы вызовете listItems в результате рендеринга метод, вы получите список, и это для одного списка, но у меня есть база данных Firebase Firestore, и я хочу l oop через эту базу данных и получить каждый документ, напечатанный как компонент React, который я назвал Service, я знаю, что вы можете не используйте JSX внутри al oop или оператора if, поэтому я попробовал это:

renderServices() {
    let db = firebase.firestore();
    var details = [[]];
    db.collection('providers').get().then(function (snapshot) {

            snapshot.forEach(function (doc) {

                details.push(
                    [
                        doc.data().owner_name,
                        doc.data().experience,
                        doc.data().charges,
                        doc.data().address,
                        doc.data().home_service,
                        doc.data().highlights,
                        doc.data().certifications,
                        doc.data().specialty,
                        doc.data().facility
                    ]
                );
                //tried loading here Serivce, didn't work
            });
        })
        .catch(function (error) {
            console.log(error);
        });
    details.map((singleDetail) =>
        (< Service details={singleDetail} />)
    );

}

, поэтому я попробовал это, но это не работает, я написал несколько журналов консоли и данные поступают правильно. Сначала я получаю весь массив «providers» документов, этот список провайдеров передается как «snapshot», так что я oop через снимок с другой функцией, и эта функция принимает один документ с именем doc и затем помещаем его в var, называемый details, который является массивом массивов, но! он не работает, массив не заполняется, даже если есть данные, и поэтому я не могу отобразить, есть идеи о том, как подойти к этому?

Ответы [ 2 ]

1 голос
/ 16 марта 2020

Я нашел решение, используя метод ReactDOM.render

Сначала создайте глобальный массив:

var Services = [];

, а затем добавьте элемент DOM, в который можно поместить и отобразить массив:

<div className="row d-flex justify-content-center" id='service-div'>

</div>

как только у вас есть элемент DOM, дайте странице загрузиться, когда загрузка завершится, будет вызван ComponentDidMount (), поэтому поместите ваш метод туда, чтобы его

ComponentDidMount(){
this.renderServices();}

теперь в этом методе просто заполните массив и затем используйте метод ReactDOM.render, чтобы отобразить его для данного элемента DOM

async renderServices() {

    let history = this.props.history; //in case the method can't access the history

    let db = firebase.firestore();
    selectedServices = this.props.location.state.selectedServices;

    var database = firebase.database();

    db.collection('providers').where('services', 'array-contains-any',
        selectedServices).get()
        .then(function (snapshot) {
            let idCount = 0;
            snapshot.forEach(function (doc) {

                let tempDetails = [];
                tempDetails.push(
                    doc.data().owner_name,
                    doc.data().experience,
                    doc.data().charges,
                    doc.data().address,
                    doc.data().home_service,
                    doc.data().highlights,
                    doc.data().certifications,
                    doc.data().specialty,
                    doc.data().facility,
                    doc.data().services,
                    doc.data().call_extension,
                    idCount.toString()
                );

                Services.push(<Service details={tempDetails} history={history} />); //adding the Service Component into a list
                idCount++;
            });
            ReactDOM.render(<div>{Services}</div>, document.getElementById('service-div')); //now rendering the entire list into the div
        }).catch(function (error) {
            console.log(error);

        });



}
1 голос
/ 11 февраля 2020

Вам необходимо разделить загрузку данных и их рендеринг, потому что получение данных составляет asynchronous, а рендеринг должен быть synchronous.

Например, в вашем случае вы нажимаете детали в массив в обратном вызове then - это произойдет async с вашей основной функцией, поэтому при вызове details.map она все еще пуста (обратный вызов не запустился для ее заполнения).

Вместо этого Вы можете загрузить данные и сохранить их в состоянии, а затем отобразить их, если они доступны. Лично я предпочитаю async/await, но тот же лог c может быть достигнут с помощью then для обещаний:

const [details, setDetails] = useState([]);

// Load the data on initial load or setup the effect to fire when reload is needed
useEffect(() => {

  // Async function that loads the data and sets the state once ready
  const loadData = async () => {
    const details = [];
    try {
      const snapshot = await db.collection('providers').get();
      snapshot.forEach((doc) => {
        details.push([
          // your details stuff
        ]);
      }
    } catch (ex) {
      // Handle any loading exceptions
    }

    setDetails(details);
  }
}, [])


// Render the available details, you could also add conditional rendering to check
// if the details are available or not yet
return (
  <div>
    {details.map((singleDetail) => (
      <Service details={singleDetail} />
    )};
  </div>
);

Если вы используете классы React вместо функциональных компонентов, вы бы вызвали загрузку из componentDidMount и все еще установить состояние после его загрузки, затем отобразить данные состояния при рендеринге.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...