Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
897 views
in Technique[技术] by (71.8m points)

reactjs - Firebase: how to add timestamp to database in firestore - where react context api is used

I am trying to add a time stamp to my firebase form data in my react app.

The app uses react context api to wrap the app in a FirebaseContext.Provider as follows:

ReactDOM.render(

  <FirebaseContext.Provider value={new Firebase()}>
    <App />

  </FirebaseContext.Provider>,
  document.getElementById('root'),
);

The context provider has:

import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
  <FirebaseContext.Consumer>
    {firebase => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);
export default FirebaseContext;

Then, each component that needs firebase is wrapped in the consumer, as follows:

import Firebase, { withFirebase } from "../../firebase"

export default withFirebase(Register)

In my submit handler, I'm trying to add a timestamp to the form data:

handleCreate = () => {

    const { form } = this.formRef.props;
    form.validateFields((err, values) => {
      if (err) {
        return;
      }
      // console.log("does it know what firebase is?", this.props.firebase.db);
    //   console.log("try time", this.props.firebase.db.FieldValue.serverTimestamp());
      console.log("it can get this far");
      console.log(this.props.firebase.firestore.FieldValue.serverTimestamp());
      console.log("it can get this far 2");

      const payload = {
        ...values,
        // role: formState.role.value,
        // created: this.props.firebase.fieldValue.serverTimestamp(),
        //  console.log("try to get a timestamp to work", this.props.firebase.serverValue.TIMESTAMP),
        // console.log("it can get to payload"),

        // createdAt: this.props.firebase.serverValue.TIMESTAMP
        // createdAt: this.props.firebase.FieldValue.serverTimestamp

        // createdAt: this.props.firebase.firestore.FieldValue.serverTimestamp(),
      }
      // console.log("formvalues", payload);


      // console.log('Received values of form: ', values);
      this.props.firebase.db
          .collection("preregistrations")
          .add(payload)
          // .set(FieldValue.serverTimestamp())

          // .add (createdAt: this.props.firebase.firestore.FieldValue.serverTimestamp());

          // .add(
          //   createdAt: this.props.firebase.firestore.FieldValue.serverTimestamp()
          // )

          // .then(docRef => {
            // resetForm(initialValues);

          // })
          .then(e => this.setState({ modalShow: true }))
          .catch(error => {
            console.error("Error adding document: ", error);
          });

      form.resetFields();
      this.setState({ visible: false });
    });

};

My firebase config is setup as follows.

import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import firestore from "firebase/firestore";


class Firebase {
  constructor() {
    app.initializeApp(config).firestore();
    this.auth = app.auth();
    // this.db = app.firebase.database()
    this.db = app.firestore();

  }  

Previously, this has worked:

createdAt: this.props.firebase.firestore.FieldValue.serverTimestamp()

The firebase documents say that FieldValue works with .set and .update. Where those of the attempts I'm making include the "FieldValue" step, I'm trying to use it with .add

The timestamp documentation uses this format to give a timestamp:

firebase. firestore.Timestamp

I've tried following this format as a line item in the payload as well as a step in sending data to the database:

createdAt: this.props.firebase.firestore.Timestamp,

Another approach that has previously worked is set out in this post. The answer and the firebase documents suggest that the timestamps only work with .set and .update, whereas I'm trying to use it with .add. Perhaps something has changed in firebase so the it no longer works with .add - but I tried adding a .set step after my .add step and that didn't work either.

this.props.firebase.db
          .collection("preregistrations")
          .add(payload)
          .set(FieldValue.serverTimestamp())

I have a tutorial that recommends using this approach.

console.log("try timestamp",  this.props.firebase.serverValue.TIMESTAMP),

It doesn't work. No error message gets generated and the console log does not run -the form just hangs and does not submit.

This tutorial comes with a book that directs to this tutorial for moving from realtime database to firestore. The only remark it makes about using timestamps is to say:

The set up for using timestamps, in this case for the createdData property for our message entities, has also changed slightly.

It does not disclose what the slight change is - but it does give 2 clues.

First - there is a repo linked to the post which has a timestamp in it like so:

  createdAt: this.props.firebase.fieldValue.serverTimestamp().

This is the same as the attempt previously made in the form submit handler.

Second - the post references this bit of the firestore documentation for how to figure out changing from realtime database to firestore. That bit of the documentation doesn't have anything to say about making a timestamp in firestore. The documentation does have an example application for FriendlyEats which has code with a table with a timestamp. It has:

 rating.timestamp = new Date();

It also has references to something removing timestamps from snapshots but I can't find the code before the example was updated to remove them so that I can find out how to add them.

This post suggests that it is necessary to import * as firebase to get the timestamps to work. If I import that, then I get a warning saying not to use the * except in development. Does this mean there is a separate package other than the ones I have imported in my firebase config (as below) that is needed to make timestamps work - and if there is - does it have a specific name - or is the * import necessary to get timestamps to work?

import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import firestore from "firebase/firestore";

I tried following the approach in that post and:

  1. imported * in the form file:

    import * as firebase from 'firebase';

  2. added the following to the payload:

    createdAt: this.props.firebase.db.Timestamp,

It doesn't work - no error messages - but the form hangs when it gets to that step.

NEXT ATTEMPT

NEXT, I tried to use:

createdAt: this.props.firebase.fieldValue.serverTimestamp(),

This is because this tutorial (which loosely refers to changes requires to use dates with firestore includes a link to a repo that uses this format).

Then in firebase.js I have a helper as:

class Firebase {
  constructor() {
    app.initializeApp(config).firestore();


    /* Firebase APIs */
    this.auth = app.auth();
    this.db = app.firestore();

    /* helpers */
    this.fieldValue = app.firestore.FieldValue;

Note that in the helper, FieldValue is upper case for Field.

When I try this, I get an error that says:

FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field createdAt)

When I try making the createdAt use similar casing in the timestamp creator (which the answer to this post suggests is correct), I try:

createdAt: this.props.firebase.FieldValue.serverTimestamp(),

This also fails. No error message but the form does not submit.

NEXT ATTEMPT

When I move the createdAt step out of the payload and just try to use in the submit handler step when the user is created in the database, like so:

TypeError: Cannot read property 'serverTimestamp' of undefined

return this.props.firebase.user(authUser.user.uid).set(
            {
              name: values.name,
              email: values.email,
              // createdAt: values.createdAt,
              createdAt: this.props.firebase.FieldValue.serverTimestamp(),

            },
            { merge: true }
          );
        })

the user set step is ignored by firebase (it does not create the record). The console error says:

TypeError: Cannot read property 'serverTimestamp' of undefined
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...