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