Reagisci: visualizza un timestamp del punto vendita


10

Sto cercando di capire come visualizzare un timestamp in un app reagire.

Ho un documento del deposito con un campo chiamato creatoAt.

Sto cercando di includerlo in un elenco di output (estraendo qui i bit pertinenti in modo da non dover leggere l'intero elenco di campi).

componentDidMount() {
    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .users()
      .onSnapshot(snapshot => {
        let users = [];

        snapshot.forEach(doc =>
          users.push({ ...doc.data(), uid: doc.id }),
        );

        this.setState({
          users,
          loading: false,
        });
      });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { users, loading } = this.state;

    return (
        <div>
    {loading && <div>Loading ...</div>}

            {users.map(user => (

                <Paragraph key={user.uid}>  

       <key={user.uid}>  
       {user.email}
       {user.name}
       {user.createdAt.toDate()}
       {user.createdAt.toDate}
       {user.createdAt.toDate()).toDateString()}

L'unico attributo che non verrà visualizzato è la data.

Ciascuno dei tentativi di cui sopra genera un errore che dice:

TypeError: impossibile leggere la proprietà 'toDate' di undefined

Ho visto questo post , questo post e questo post , e questo post e altri simili, che suggeriscono che toDate () dovrebbe funzionare. Ma - questa estensione genera un errore per me - anche quando provo l'estensione toString.

So che sa che c'è qualcosa nel negozio di alimentari perché quando provo user.createdAt, ricevo un errore dicendo che ha trovato un oggetto con secondi al suo interno.

Prendendo l'esempio da Waelmas di seguito, ho provato a registrare l'output del campo come:

this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
  console.log(doc.data().createdAt.toDate());

}

Ho anche provato ad aggiungere questo alla mia istruzione sulla mappa ma ho ricevuto un errore che diceva che user.get non è una funzione.

{user.get().then(function(doc) {
                    console.log(doc.data().createdAt.toDate());}
                  )}

Genera lo stesso messaggio di errore di cui sopra.

inserisci qui la descrizione dell'immagine

PROSSIMO TENTATIVO

Una cosa strana che è emersa nel tentativo di trovare un modo per registrare una data in Firestore che mi permetta di rileggerla, è che quando cambio il mio gestore di invio in una forma per usare questa formulazione:

handleCreate = (event) => {
    const { form } = this.formRef.props;
    form.validateFields((err, values) => {
      if (err) {
        return;
      };
    const payload = {
    name: values.name,
    // createdAt: this.fieldValue.Timestamp()
    // createdAt: this.props.firebase.fieldValue.serverTimestamp()

    }
    console.log("formvalues", payload);
    // console.log(_firebase.fieldValue.serverTimestamp());


    this.props.firebase
    .doCreateUserWithEmailAndPassword(values.email, values.password)
    .then(authUser => {
    return this.props.firebase.user(authUser.user.uid).set(
        {
          name: values.name,
          email: values.email,
          createdAt: new Date()
          // .toISOString()
          // createdAt: this.props.firebase.fieldValue.serverTimestamp()

        },
        { merge: true },
    );
    // console.log(this.props.firebase.fieldValue.serverTimestamp())
    })
    .then(() => {
      return this.props.firebase.doSendEmailVerification();
      })
    // .then(() => {message.success("Success") })
    .then(() => {
      this.setState({ ...initialValues });
      this.props.history.push(ROUTES.DASHBOARD);

    })


  });
  event.preventDefault();
    };

Funziona per registrare una data nel database.

La forma della voce del camino è simile alla seguente:

inserisci qui la descrizione dell'immagine

Sto cercando di visualizzare una data in questo componente:

class UserList extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      users: [],
    };
  }

  componentDidMount() {
    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .users()
      .onSnapshot(snapshot => {
        let users = [];

        snapshot.forEach(doc =>
          users.push({ ...doc.data(), uid: doc.id }),
        );

        this.setState({
          users,
          loading: false,
        });
      });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { users, loading } = this.state;

    return (
      <div>
          {loading && <div>Loading ...</div>}

          <List
            itemLayout="horizontal"
            dataSource={users}

            renderItem={item => (
              <List.Item key={item.uid}>
                <List.Item.Meta
                  title={item.name}
                  description={item.organisation}
                />
                  {item.email}
                  {item.createdAt}
                  {item.createdAt.toDate()}
                  {item.createdAt.toDate().toISOString()}

              </List.Item>
            // )
          )}
          />

      </div>
    );
  }
}

export default withFirebase(UserList);

Quando provo a rileggerlo, usando:

{} Item.email

Il messaggio di errore dice:

Errore: gli oggetti non sono validi come figlio React (trovato: Timestamp (secondi = 1576363035, nanosecondi = 52000000)). Se intendevi eseguire il rendering di una raccolta di elementi secondari, utilizza invece un array. nell'articolo (su UserIndex.jsx: 74)

Quando provo a usare ciascuno di questi tentativi:

{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}

Viene visualizzato un errore che dice:

TypeError: impossibile leggere la proprietà 'toDate' di undefined

In base alla capacità di rileggere le voci registrate nello stesso documento in altri campi, mi aspetto che una di queste funzioni per produrre output, anche se non è formattata nel modo desiderato. Questo non succede.

PROSSIMO TENTATIVO

Prendendo l'esempio di Waelmas, ho provato a seguire le istruzioni, ma dove non stiamo ottenendo la stessa risposta è nel primo passo. Dove Walemas ottiene un output basato sull'estensione .toDate (), ricevo un errore che dice che la data () non è una funzione.

Coerentemente con la documentazione di Firebase, ho provato:

    const docRef = this.props.firebase.db.collection("users").doc("HnH5TeCU1lUjeTqAYJ34ycjt78w22");

docRef.get().then(function(docRef) {
    if (doc.exists) {
        console.log("Document createdAt:", docRef.createdAt.toDate());

}})

Questo produce una serie di errori con la sintassi e non riesco a trovare un modo per aggirarli.

PROSSIMO TENTATIVO

Ho quindi provato a creare un nuovo modulo per vedere se potevo esplorare questo senza l'aspetto di autenticazione del modulo degli utenti.

Ho un modulo che accetta input come:

this.props.firebase.db.collection("insights").add({
            title: title,
            text: text,
            // createdAt1: new Date(),
            createdAt: this.props.firebase.fieldValue.serverTimestamp()
        })

Dove nel modulo precedente, il nuovo tentativo Date () ha funzionato per registrare una data nel database, in questo esempio entrambi i campi per CreatedAt e CreatedAt1 generano la stessa voce del database:

inserisci qui la descrizione dell'immagine

<div>{item.createdAt.toDate()}</div>
                    <div>{item.createdAt.toDate()}</div>

Quando provo a generare il valore delle date, il primo genera un errore che dice:

Gli oggetti non sono validi come figlio React (trovato: dom 15 dicembre 2019 21:33:32 GMT + 1100 (ora legale orientale australiana)). Se intendevi eseguire il rendering di una raccolta di elementi secondari, utilizza invece un array

Il secondo genera l'errore dicendo:

TypeError: impossibile leggere la proprietà 'toDate' di undefined

Sono bloccato per idee su cosa provare dopo.

Ho visto questo post che suggerisce che quanto segue potrebbe fare qualcosa di utile:

                {item.createdAt1.Date.valueOf()}

Non Viene visualizzato un errore che dice:

TypeError: impossibile leggere la proprietà 'Date' di undefined

Questo post sembra avere i miei stessi problemi, ma non spiega come sono riusciti a visualizzare il valore della data memorizzato.

Questo post sembra rimanere bloccato al messaggio di errore dell'array, ma sembra aver capito come visualizzare una data usando CreatedAt.toDate ()

Risposte:


1

Dopo alcune discussioni, abbiamo scoperto che i timestamp nell'oggetto utente OP potevano essere renderizzati come tali:

render() { 
const { users, loading } = this.state; 

return ( 
    <div> 
        {loading && <div>Loading ...</div>} 

        {users.map(user => ( 

            <Paragraph key={user.uid}> 

                <key={user.uid}> 
                    {user.email} 
                    {user.name} 
                    {new Date(user.createdAt.seconds * 1000).toLocaleDateString("en-US")}

Ho ricreato il tuo esempio in un finto progetto React e ho ricevuto lo stesso errore previsto.

Errore: gli oggetti non sono validi come figlio React

Sono stato in grado di ottenere questo per il rendering corretto con il seguente metodo, che dovrebbe funzionare anche per te:

{new Date(user.createdAt._seconds * 1000).toLocaleDateString("en-US")}

Che, per il mio esempio di data e ora, reso come:

2019/12/30


Assicurati di utilizzare un timestamp che è stato salvato in Firestore come:

createdAt: this.props.firebase.Timestamp.fromDate(new Date())

Nota: si presume che l'istanza di firebase.firestore()sia a this.props.firebase. In altri esempi usi this.props.firebase, ma quei metodi sembrano metodi di aiuto che hai creato tu stesso.

Quando questo valore viene recuperato, sarà un oggetto con due proprietà - _secondse _nanoseconds.

Assicurati di includere il carattere di sottolineatura. Se lo usi createdAt.secondsnon funzionerà, deve esserlo createdAt._seconds.


Altre cose che ho provato:

user.createdAt.toDate()genera toDate() is not a function.

user.createdAt getta Error: Objects are not valid as a React child

new Date(user.createdAt._nanoseconds) rende la data sbagliata


Ciao - grazie per il suggerimento. Ho provato questo e ho ricevuto un errore che dice: TypeError: Impossibile leggere la proprietà 'Timestamp' di undefined
Mel

Ho anche provato: CreatedAt: firebase.firestore.fieldValue.serverTimestamp (). FromDate (new Date ()), che restituisce un errore che dice: TypeError: Impossibile leggere la proprietà 'fieldValue' di undefined
Mel

Anche se questo non ha funzionato per me, sono interessato a capire come sei arrivato a pensare di provare il formato che hai usato. Non è come mostrato nella documentazione. Se posso imparare come hai scoperto qualcosa che funziona per te, potrebbe farmi trovare un modo che funzioni per me (non capisco perché quelli non sono la stessa cosa per tutti - ma ho bisogno di nuove idee per le cose da provare ). Grazie ancora per aver cercato di aiutare.
Mel

Quello che posso fare è salvare una data (come mostrato sopra) usando: CreatedAt: this.props.firebase.fieldValue.serverTimestamp (),
Mel


5

Quando ottieni i timestamp da Firestore, sono del seguente tipo:

inserisci qui la descrizione dell'immagine

Per convertirlo in un normale timestamp puoi usare la funzione .toDate ().

Ad esempio, per un documento come il seguente:

inserisci qui la descrizione dell'immagine

Possiamo usare qualcosa come:

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  console.log(doc.data().[FIELD].toDate());
});

e l'output sarà come:

2019-12-16T16:27:33.031Z

Ora per elaborare ulteriormente quel timestamp, è possibile convertirlo in una stringa e utilizzare regex per modificarlo in base alle proprie esigenze.

Ad esempio: (sto usando Node.js qui)

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  var stringified = doc.data().[FIELD].toDate().toISOString();
  //console.log(stringified);
  var split1 = stringified.split('T');
  var date = split1[0].replace(/\-/g, ' ');
  console.log(date);
  var time = split1[1].split('.');
  console.log(time[0]);
});

Ti darà un output come questo:

inserisci qui la descrizione dell'immagine


Grazie per l'esempio Ho la stessa struttura nel mio tentativo. Funziona per restituire tutti i valori di stringa nel documento ma non la data. Invece, genera un errore con il messaggio che ho postato sopra. Non ha alcun senso. Ho provato ad aggiungere l'estensione toISOString () ma non cambia il messaggio di errore (che dovrebbe essere solo la formattazione)
Mel

Puoi registrare il valore del timestamp nella console? Solo per confermare che è il tipo corretto di data / ora Firestore. @Mel
Waelmas,

No - il registro della console non funziona - genera anche un errore - ma la data viene registrata nel campo CreatedAt nella tabella - ora sto solo cercando di rileggerlo. Ho creato un post che spiega come ho ottenuto la data di registrazione (non per la documentazione di firebase) qui: stackoverflow.com/questions/59257755/…
Mel

Dal momento che stai seguendo un approccio diverso da quello raccomandato dai documenti ufficiali, non sono sicuro di cosa stia davvero andando storto. Sembra che il modo in cui stai creando e spingendo il timestamp in primo luogo sia in qualche modo difettoso. Quando memorizzi un timestamp su Firestore, questo deve essere un oggetto del formato che ho citato all'inizio della mia risposta. In questo modo viene riconosciuto come timestamp valido che può quindi essere utilizzato con .toDate (). Firestore.Timestamp.now () ti darà un timestamp del formato corretto per verificarlo. @Mel
Waelmas,

Ho provato a seguire la documentazione ufficiale per creare un timestamp. Non riuscivo a farlo funzionare. Mi sono imbattuto in un modo alternativo per registrare una data e ora non riesco a rileggere l'output! Così frustrante. Grazie comunque per aver cercato di aiutare.
Mel

2

Quindi il negozio di alimentari immagazzina le date come un oggetto con secondi e nanosecondi. Se desideri il tempo in cui l'utente è stato creato, faresti riferimentouser.createdAt.nanoseconds . Questo restituisce un timestamp unix.

Come vuoi visualizzare la data nella tua app? Se si desidera ottenere un oggetto data, è possibile passare il timestamp in un costruttore di date in questo modo new Date(user.createdAt.nanoseconds). Personalmente mi piace usare la libreria date-fns per gestire il tempo.


Grazie - ho provato questo suggerimento. Restituisce un errore che dice: TypeError: impossibile leggere la proprietà 'nanosecondi' di undefined. Dare un'occhiata alla biblioteca che hai suggerito ora
Mel

Puoi accedere creato e condividere per favore. Data la natura asincrona dei dati, probabilmente dovrai semplicemente restituirli in questo modo user.createdAt && new Date(user.createdAt.nanoseconds). Date-fns non aiuterà con questo problema, che è solo una comoda libreria per visualizzare la data dopo averla.
Josh Pittman,

CreatedAt registra un lungo elenco di menu a discesa. Non riesco a trovarne uno contenente la data indicata nel campo nel negozio di alimentari. La prima parte è: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : costruttore FieldValueImpl: ServerTimestampFieldValueImpl ƒ () esempio: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : costruttore FieldValueImpl: ƒ ServerTimestampFieldValueImpl () esempio: ServerTimestampFieldValueImpl {_methodName: " Argomenti FieldValue.serverTimestamp "}: (...) chiamante: (...)
Mel

Sembra che tu abbia trasferito la funzione timestamp nel database, non un timestamp effettivo. Come si imposta il timestamp? firestore.FieldValue.serverTimestamp()
Josh Pittman,

La voce che mostra nel negozio di alimentari è la foto che ho allegato. Questa è la voce: this.props.firebase.fieldValue.serverTimestamp ()
Mel

2

Come inviare la data a Firestore:

import firebase from 'firebase/app';

// ..........
// someObject is the object you're saving to your Firestore.

someObject.createdAt: firebase.firestore.Timestamp.fromDate(new Date())

Come rileggerlo:

function mapMonth(monthIndex) {
  const months = {
    0: 'jan',
    1: 'feb',
    2: 'mar',
    3: 'apr',
    4: 'may',
    5: 'jun',
    6: 'jul',
    7: 'aug',
    8: 'sep',
    9: 'oct',
    10: 'nov',
    11: 'dec'
  };
  return months[monthIndex];
}

// ..........
// Here you already read the object from Firestore and send its properties as props to this component.

return(
    <LS.PostDate_DIV>
      Published on {mapMonth(props.createdAt.toDate().getMonth()) + ' '}
      of {props.createdAt.toDate().getFullYear()}
    </LS.PostDate_DIV>
  );
}

Fondamentalmente quando lo fai createdAt.toDate()ottieni un oggetto JS Date.

Lo uso sempre così!

Da: https://cloud.google.com/firestore/docs/manage-data/add-data

inserisci qui la descrizione dell'immagine

Questo creerà un dato basato sulla data di sistema dell'utente. Se devi essere sicuro che tutto sarà archiviato in ordine cronologico (senza errori di date di sistema errate impostate dal tuo sistema utenti) sul tuo DB, dovresti usare un timestamp del server. La data verrà impostata utilizzando il sistema di date interno Firestore DB.

inserisci qui la descrizione dell'immagine


Grazie per questo, ma il problema che sto cercando di superare è che non riesco a trovare un modo per visualizzare la data registrata nel database. Continuo a ricevere errori dei tipi che ho condiviso.
Mel

2

Con un ID documento di un utente per il quale è createdAtimpostata la proprietà, provare quanto segue:

const docRef = db.collection("users").doc("[docID]");

docRef.get().then(function(docRef) {
  if (docRef.exists) {
     console.log("user created at:", docRef.data().createdAt.toDate());
  }
})

È importante chiamare il .data()metodo prima di accedere alle proprietà del documento

Si noti che se si accede a docRef.data().createdAt.toDate()un utente per il quale createdAtnon è impostata la proprietà, si otterràTypeError: Cannot read property 'toDate' of undefined

Quindi, nel caso abbiate un utente nella vostra raccolta che non ha createdAtproprietà definite. È necessario implementare una logica per verificare se l'utente ha la createdAtproprietà prima di ottenerla. Puoi fare qualcosa del genere:

//This code gets all the users and logs it's creation date in the console
docRef.get().then(function(docRef) {
  if (docRef.exists && docRef.data().createdAt) {
      console.log("User created at:", docRef.data().createdAt.toDate());
  }
})

Come puoi vedere sopra, utilizzo i dati () nelle mie richieste per i campi del documento. Se non lo facessi, gli altri campi non verrebbero visualizzati. Il problema specifico riguarda il timestamp, che non viene visualizzato. Uno dei tentativi che ho fatto, e che ho indicato sopra, include il tentativo di utilizzare l'estensione toDate (). Non funziona, per i motivi indicati sopra. Grazie comunque per il tuo tempo.
Mel,

0

In passato ho riscontrato problemi con le proprietà degli oggetti nidificati che non venivano visualizzate correttamente nelle liste in cui item.somePropè considerato un oggetto, ma item.someProp.someSubPropnon si risolvono con il valore di someSubPropin item.someProp.

Quindi, per aggirare il problema, perché non valutare Timestamp su un semplice oggetto data (o il formato di visualizzazione desiderato) quando si crea l'oggetto utente?

this.unsubscribe = this.props.firebase
  .users()
  .onSnapshot(snapshot => {
    let users = [];

    snapshot.forEach(doc =>
      let docData = doc.data();
      docData.createdAt = docData.createdAt.toDate();
      users.push({ ...docData, uid: doc.id }),
    );

    this.setState({
      users,
      loading: false,
    });
  });

Vale anche la pena notare che entrambi DocumentSnapshot#data()e DocumentSnapshot#get()accettare un oggetto che specifica come gestire FieldValue.serverTimestamp()valori non ancora finalizzati . Per impostazione predefinita, un non ancora finalizzato sarà semplicemente nullo. L'utilizzo { serverTimestamps: "estimate"}modificherà questi valori null in una stima.
Samthecodingman,

Ciao - grazie per il suggerimento. Mi piacerebbe provarlo ma non lo capisco - o come posso provare a implementarlo. Esiste una convenzione per i principi che stai applicando per elaborare questo suggerimento. Se riesco a trovare pubblicazioni sull'approccio, cercherò di capire come funziona la tua idea in modo che io possa provarla nel mio codice.
Mel

Non ho alcuna risorsa particolare per questo, come l'ho raccolto dopo aver esaminato altre domande StackOverflow nel corso degli anni.
samthecodingman,

Grazie per la condivisione. Leggerò questi stasera
Mel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.