web-dev-qa-db-fra.com

React - affiche un horodatage Firestore

J'essaie de comprendre comment afficher un horodatage Firestore dans une application React.

J'ai un document Firestore avec un champ nommé createdAt.

J'essaie de l'inclure dans une liste de sortie (en extrayant les bits pertinents ici afin que vous n'ayez pas à lire toute la liste des champs).

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()}

Le seul attribut qui ne sera pas rendu est la date.

Chacune des tentatives ci-dessus génère une erreur qui dit:

TypeError: Impossible de lire la propriété 'toDate' de indéfini

J'ai vu ce post , et ce post et ce post , et ce post et d'autres comme eux, qui suggèrent que toDate () devrait fonctionner. Mais - cette extension génère une erreur pour moi - y compris lorsque j'essaye l'extension toString.

Je sais qu'il sait qu'il y a quelque chose dans firestore parce que lorsque j'essaye user.createdAt, j'obtiens une erreur disant qu'il a trouvé un objet avec des secondes dedans.

En prenant l'exemple de Waelmas ci-dessous, j'ai essayé de consigner la sortie du champ comme suit:

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

}

J'ai également essayé d'ajouter cela à ma déclaration de carte, mais j'obtiens une erreur indiquant que user.get n'est pas une fonction.

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

Il génère le même message d'erreur que ci-dessus.

enter image description here

PROCHAINE TENTATIVE

Une chose étrange qui est survenue en essayant de trouver un moyen d'enregistrer une date dans Firestore qui me permette de la relire ensuite, c'est que lorsque je change de gestionnaire de soumission sous une forme pour utiliser cette formulation:

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();
    };

Cela fonctionne pour enregistrer une date dans la base de données.

La forme de l'entrée Firestore ressemble à ceci:

enter image description here

J'essaie d'afficher une date dans ce composant:

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);

Quand j'essaye de le relire - en utilisant:

{item.email}

Le message d'erreur se lit comme suit:

Erreur: les objets ne sont pas valides en tant qu'enfants React (trouvé: horodatage (secondes = 1576363035, nanosecondes = 52000000)). Si vous vouliez rendre une collection d'enfants, utilisez plutôt un tableau. Dans Article (sur UserIndex.jsx: 74)

Lorsque j'essaie d'utiliser chacune de ces tentatives:

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

Je reçois une erreur qui dit:

TypeError: Impossible de lire la propriété 'toDate' de indéfini

Sur la base de la possibilité de relire les entrées enregistrées dans le même document dans d'autres champs, je m'attends à ce que l'une d'entre elles fonctionne pour produire une sortie, même si elle n'est pas formatée comme je le souhaite. Cela n'arrive pas.

PROCHAINE TENTATIVE

En prenant l'exemple de Waelmas, j'ai essayé de suivre les instructions, mais là où nous n'obtenons pas la même réponse, c'est dans la première étape. Lorsque Walemas obtient une sortie basée sur l'extension .toDate (), j'obtiens une erreur disant que toDate () n'est pas une fonction.

Conformément à la documentation de Firebase, j'ai essayé:

    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());

}})

Cela produit une chaîne d'erreurs avec la syntaxe et je ne peux pas trouver un moyen de les contourner.

PROCHAINE TENTATIVE

J'ai ensuite essayé de créer un nouveau formulaire pour voir si je pouvais l'explorer sans l'aspect authentification du formulaire utilisateurs.

J'ai un formulaire qui prend en entrée:

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

Dans le formulaire précédent, la nouvelle tentative Date () a fonctionné pour enregistrer une date dans la base de données, dans cet exemple, les deux champs pour createdAt et createdAt1 génèrent la même entrée de base de données:

enter image description here

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

Lorsque j'essaie de sortir la valeur des dates, la première génère une erreur qui dit:

Les objets ne sont pas valides en tant qu'enfants React (trouvé: dim. 15 déc 2019 21:33:32 GMT + 1100 (Australian Eastern Daylight Time)). Si vous vouliez rendre une collection d'enfants, utilisez un tableau à la place

Le second génère l'erreur en disant:

TypeError: Impossible de lire la propriété 'toDate' de indéfini

Je suis coincé pour des idées sur quoi essayer ensuite.

J'ai vu ce post qui suggère que ce qui suit pourrait faire quelque chose d'utile:

                {item.createdAt1.Date.valueOf()}

Ce n'est pas le cas. Il rend une erreur qui dit:

TypeError: Impossible de lire la propriété 'Date' de non défini

Ce post semble avoir le même problème que moi, mais n'entre pas dans la façon dont ils ont réussi à afficher la valeur de date qu'ils ont stockée.

Ce post semble être bloqué sur le message d'erreur du tableau, mais semble avoir trouvé comment afficher une date à l'aide de createdAt.toDate ()

10
Mel

Après quelques discussions, nous avons constaté que les horodatages dans l'objet utilisateur OPs pouvaient être des rendus en tant que tels:

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")}

J'ai recréé votre exemple dans un projet factice React project, et j'ai reçu la même erreur que prévu.

Erreur: les objets ne sont pas valides en tant qu'enfants React

J'ai pu obtenir ce rendu correctement avec la méthode suivante, qui devrait également fonctionner pour vous:

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

Qui, pour mon exemple d'horodatage, rendu comme:

30/12/2019


Assurez-vous que vous utilisez un horodatage enregistré dans Firestore en tant que:

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

Remarque: Cela suppose que votre instance de firebase.firestore() est à this.props.firebase. Dans d'autres exemples, vous utilisez this.props.firebase, mais ces méthodes ressemblent à des méthodes d'assistance que vous avez créées vous-même.

Lorsque cette valeur est récupérée, ce sera un objet avec deux propriétés - _seconds Et _nanoseconds.

Assurez-vous d'inclure le trait de soulignement. Si vous utilisez createdAt.seconds Cela ne fonctionnera pas, il doit être createdAt._seconds.


J'ai essayé d'autres choses:

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

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

new Date(user.createdAt._nanoseconds) rend la mauvaise date

1
Michael Rodriguez

J'ai rencontré des problèmes dans le passé avec des propriétés d'objets imbriquées qui ne s'affichent pas correctement dans les listes où item.someProp est considéré comme un objet, mais item.someProp.someSubProp ne se résoudra pas avec la valeur de someSubProp dans item.someProp.

Donc, pour contourner le problème, pourquoi ne pas évaluer l'horodatage en un objet de date ordinaire (ou le format d'affichage souhaité) lors de la création de l'objet utilisateur?

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,
    });
  });
0
samthecodingman