Reactjs 使用React类组件从firebase获取数据需要渲染两次甚至更多

Reactjs 使用React类组件从firebase获取数据需要渲染两次甚至更多,reactjs,firebase,google-cloud-firestore,components,Reactjs,Firebase,Google Cloud Firestore,Components,我一直在努力使这项工作,但它不工作 这是我的代码: import './App.css'; import React from 'react' import { Button, TextField } from '@material-ui/core'; import Todo from './components/Todo'; import db from './firebase'; import { Grid } from '@material-ui/core'; import firebas

我一直在努力使这项工作,但它不工作

这是我的代码:

import './App.css';
import React from 'react'
import { Button, TextField } from '@material-ui/core';
import Todo from './components/Todo';
import db from './firebase';
import { Grid } from '@material-ui/core';
import firebase from 'firebase';

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      todos: [],
      input: ''
    }
  }

  componentWillMount() {
    let tmp_todos = this.state.todos;
    db.collection('todos').orderBy('timestamp', 'desc').onSnapshot( snapshot => {
      snapshot.forEach( doc => {
        tmp_todos.push(doc.data().text);
      });
      this.setState({
        todos: tmp_todos
      });
    })
  }

  setInput(value){
    this.setState({
      input: value
    })
  }

  submitTodo(event){
    event.preventDefault();

    db.collection('todos').add({
      text: this.state.input,
      timestamp: firebase.firestore.FieldValue.serverTimestamp()
    })

    this.setState({
      input: ''
    })
  }

  addTodo(todo){
    return [...this.state.todos, todo];
  }

  render(){

    return (
      <div className="App">
        <h1>Hello les proooo Whenever your callback gets called with data from Firestore, the 
snapshot
contains all data that exists at the location. So the first time it contains all initial todos, but then if you add one: you get called with all the previous ones, and the new one.

So you code will have to deal with that. You can either determine the changes between the snapshots, or (much simpler) you can clear the list of todo's whenever you get an update:

let tmp_todos = [];
db.collection('todos').orderBy('timestamp', 'desc').onSnapshot( snapshot => {
  snapshot.forEach( doc => {
    tmp_todos.push(doc.data().text);
  });
  this.setState({
    todos: tmp_todos
  });
})
import'/App.css';
从“React”导入React
从“@material ui/core”导入{按钮,TextField};
从“./components/Todo”导入Todo;
从“/firebase”导入数据库;
从'@material ui/core'导入{Grid};
从“firebase”导入firebase;
类应用程序扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
待办事项:[],
输入:“”
}
}
组件willmount(){
让tmp_todos=this.state.todos;
db.collection('todos').orderBy('timestamp','desc').onSnapshot(快照=>{
snapshot.forEach(doc=>{
tmp_todos.push(doc.data().text);
});
这是我的国家({
待办事项:tmp_待办事项
});
})
}
设置输入(值){
这是我的国家({
输入:值
})
}
submitTodo(事件){
event.preventDefault();
db.collection('todos')。添加({
文本:this.state.input,
时间戳:firebase.firestore.FieldValue.serverTimestamp()
})
这是我的国家({
输入:“”
})
}
添加todo(todo){
返回[…this.state.todos,todo];
}
render(){
返回(

Hello les proooo每当使用Firestore中的数据调用回调时,
快照
包含该位置存在的所有数据。因此,第一次它包含所有初始TODO,但如果添加一个,则会使用之前的所有TODO和新TODO调用

因此,您的代码将必须处理此问题。您可以,或者(更简单)您可以在获得更新时清除todo列表:

db.collection('todos').orderBy('timestamp', 'desc').onSnapshot( snapshot => {
  this.setState({
    todos: snapshot.docs.map(doc => doc.data().text)
  });
})

或者简化一点:


谢谢@FrankVanPuffelen,第二种方法称为简化版,效果非常好。但是,我必须将临时TODO创建为空数组的第一种方法不起作用,我在发布问题之前就尝试过。再次感谢