Реагировать на рендеринг приложения до загрузки данных Firestore - PullRequest
0 голосов
/ 09 февраля 2019

Я пытаюсь загрузить данные из Firestore и показать их на диаграмме Ганта, но она рендерится до того, как загрузит данные из firebase.Поэтому я вызываю setState внутри componentDidMount, потому что я думал, что тогда он снова вызовет рендер, и в этот момент данные будут там.Но он все еще сидит пустым.Есть идеи, почему?

import React, { Component } from 'react';
import Gantt from './Gantt';
import Toolbar from './Toolbar';
import MessageArea from './MessageArea';
import Firebase from './Firebase';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentZoom: 'Days',
      messages: [],
      projects: [],
      links: []
    };

    this.handleZoomChange = this.handleZoomChange.bind(this);
    this.logTaskUpdate = this.logTaskUpdate.bind(this);
    this.logLinkUpdate = this.logLinkUpdate.bind(this);
  }

  componentDidMount() {
    const db = Firebase.firestore();
    var projectsArr = [];
    db.collection('projects').get().then((snapshot) => {
        snapshot.docs.forEach(doc => {
            let project = doc.data();
            projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
        });
    });

    this.setState({
      projects: projectsArr
    });
  }

  addMessage(message) {
    var messages = this.state.messages.slice();
    var prevKey = messages.length ? messages[0].key: 0;

    messages.unshift({key: prevKey + 1, message});
    if(messages.length > 40){
      messages.pop();
    }
    this.setState({messages});
  }

  logTaskUpdate(id, mode, task) {
    let text = task && task.text ? ` (${task.text})`: '';
    let message = `Task ${mode}: ${id} ${text}`;
    this.addMessage(message);
  }

  logLinkUpdate(id, mode, link) {
    let message = `Link ${mode}: ${id}`;
    if (link) {
      message += ` ( source: ${link.source}, target: ${link.target} )`;
    }
    this.addMessage(message)
  }

  handleZoomChange(zoom) {
    this.setState({
      currentZoom: zoom
    });
  }  

  render() {

    var projectData = {data: this.state.projects, links: this.state.links};

    return (
      <div>
        <Toolbar
            zoom={this.state.currentZoom}
            onZoomChange={this.handleZoomChange}
        />
        <div className="gantt-container">
          <Gantt
            tasks={projectData}
            zoom={this.state.currentZoom}
            onTaskUpdated={this.logTaskUpdate}
            onLinkUpdated={this.logLinkUpdate}
          />
        </div>
        <MessageArea
            messages={this.state.messages}
        />
      </div>
    );
  }
}
export default App;

1 Ответ

0 голосов
/ 09 февраля 2019

Вы звоните setState за пределами then обратного вызова.

Так что измените

   db.collection('projects').get().then((snapshot) => {
         snapshot.docs.forEach(doc => {
             let project = doc.data();
             projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
         });
     });

     this.setState({
       projects: projectsArr
     });

на

   db.collection('projects').get().then((snapshot) => {
        snapshot.docs.forEach(doc => {
             let project = doc.data();
             projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
         });
        this.setState({
             projects: projectsArr
        });
});

Кроме того, как общий шаблонВы можете сделать что-то вроде этого:

<code>    class AsyncLoad extends React.Component {
      state = { data: null }

      componentDidMount () {
        setTimeout(() => {
          this.setState({ data: [1, 2, 3]})
        }, 3000)
      }

      render () {
        const { data } = this.state
        if (!data) { return <div>Loading...</div> }
        return (
          <pre>{JSON.stringify(data, null, 4)}
)}}

Это достаточно распространенная операция для создания для нее HOC.

...