Próbuję wymyślić, jak wyświetlać znacznik czasu w sklepie z aplikacjami.
Mam dokument ze sklepu ogniowego z polem o nazwie utworzony.
Próbuję dołączyć go do listy wyników (wyodrębniając odpowiednie bity tutaj, abyś nie musiał czytać całej listy pól).
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()}
Jedynym atrybutem, który nie będzie renderowany, jest data.
Każda z powyższych prób generuje błąd, który mówi:
TypeError: Nie można odczytać właściwości „toDate” niezdefiniowanej
Widziałem ten post , ten post i ten post , oraz ten post i inni lubią je, co sugeruje, że toDate () powinno działać. Ale - to rozszerzenie generuje dla mnie błąd - także wtedy, gdy próbuję rozszerzenia toString.
Wiem, że wie, że w firestore jest coś, ponieważ kiedy próbuję user.createdAt, pojawia się błąd informujący, że znalazł obiekt z sekundami.
Biorąc przykład z Waelmas poniżej, próbowałem zapisać dane wyjściowe pola jako:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
console.log(doc.data().createdAt.toDate());
}
Próbowałem również dodać to do mojej instrukcji map, ale pojawia się błąd, który mówi, że user.get nie jest funkcją.
{user.get().then(function(doc) {
console.log(doc.data().createdAt.toDate());}
)}
Generuje taki sam komunikat o błędzie jak powyżej.
NASTĘPNA PRÓBA
Jedną z dziwnych rzeczy, które pojawiły się, gdy próbowałem znaleźć sposób na zapisanie daty w Firestore, która pozwala mi ją później przeczytać, jest to, że kiedy zmieniam moduł obsługi przesyłania w jednej formie, aby użyć tego sformułowania:
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();
};
To działa, aby zapisać datę w bazie danych.
Forma wpisu do firestore wygląda następująco:
Próbuję wyświetlić datę w tym komponencie:
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);
Kiedy próbuję go odczytać - używając:
{item.email}
Komunikat o błędzie brzmi:
Błąd: Obiekty nie są poprawne jako dziecko React (znaleziono: Znacznik czasu (sekundy = 1576363035, nanosekundy = 52000000)). Jeśli chcesz wyrenderować zbiór dzieci, użyj zamiast tego tablicy. w elemencie (w UserIndex.jsx: 74)
Kiedy próbuję użyć każdej z tych prób:
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
Pojawia się komunikat o błędzie:
TypeError: Nie można odczytać właściwości „toDate” niezdefiniowanej
Opierając się na możliwości odczytywania wpisów zapisanych w tym samym dokumencie w innych polach, oczekuję, że którekolwiek z nich zadziałają, generując dane wyjściowe, nawet jeśli nie zostaną sformatowane w sposób, jaki chcę. To się nie zdarza.
NASTĘPNA PRÓBA
Biorąc przykład Waelmasa, próbowałem postępować zgodnie z instrukcjami, ale tam, gdzie nie otrzymujemy takiej samej odpowiedzi, jest pierwszy krok. Gdy Walemas otrzymuje dane wyjściowe oparte na rozszerzeniu .toDate (), pojawia się błąd informujący, że toDate () nie jest funkcją.
Zgodnie z dokumentacją Firebase próbowałem:
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());
}})
Powoduje to szereg błędów w składni i nie mogę znaleźć sposobu na ich obejście.
NASTĘPNA PRÓBA
Następnie próbowałem utworzyć nowy formularz, aby sprawdzić, czy mogę to zbadać bez aspektu uwierzytelniania formularza użytkownika.
Mam formularz, który przyjmuje dane wejściowe jako:
this.props.firebase.db.collection("insights").add({
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
})
Tam, gdzie w poprzedniej formie nowa próba Date () pracowała nad zapisaniem daty w bazie danych, w tym przykładzie oba pola dla createAt i CreatedAt1 generują ten sam wpis w bazie danych:
<div>{item.createdAt.toDate()}</div>
<div>{item.createdAt.toDate()}</div>
Gdy próbuję wyprowadzić wartość dat, pierwsza generuje błąd, który mówi:
Obiekty nie są ważne jako dziecko React (znaleziono: niedz. 15 grudnia 2019 21:33:32 GMT + 1100 (australijski wschodni czas letni)). Jeśli chcesz wyrenderować zbiór dzieci, użyj zamiast tego tablicy
Drugi generuje błąd, mówiąc:
TypeError: Nie można odczytać właściwości „toDate” niezdefiniowanej
Utknąłem na pomysłach, co dalej.
Widziałem ten post, który sugeruje, że następujące czynności mogą zrobić coś pożytecznego:
{item.createdAt1.Date.valueOf()}
Tak nie jest. Wyświetla błąd, który mówi:
TypeError: Nie można odczytać właściwości „Data” niezdefiniowanej
Ten post wydaje się mieć takie same problemy jak ja, ale nie opisuje, w jaki sposób udało im się wyświetlić przechowywaną wartość daty.
Wydaje się, że ten wpis utknął w komunikacie o błędzie tablicy, ale wydaje się, że wymyślił sposób wyświetlania daty za pomocą metody createAt.toDate ()
Gdy otrzymujesz znaczniki czasu z Firestore, są one następującego typu:
Aby przekonwertować to na normalny znacznik czasu, możesz użyć funkcji .toDate ().
Na przykład dla dokumentu podobnego do następującego:
Możemy użyć czegoś takiego jak:
a wynik będzie taki jak:
Aby dalej przetwarzać ten znacznik czasu, możesz przekonwertować go na ciąg znaków i użyć wyrażenia regularnego, aby zmodyfikować go zgodnie z własnymi potrzebami.
Na przykład: (Używam tutaj Node.js)
Otrzymasz takie wyjście:
źródło
Dlatego firestore przechowuje daty jako obiekt z sekundami i nanosekundami. Jeśli chcesz, czas, w którym użytkownik został utworzony, powinieneś odwołać się
user.createdAt.nanoseconds
. Zwraca znacznik czasu unix.Jak chcesz wyświetlać datę w aplikacji? Jeśli chcesz uzyskać obiekt daty, możesz przekazać znacznik czasu do takiego konstruktora daty
new Date(user.createdAt.nanoseconds)
. Osobiście lubię korzystać z biblioteki date-fns do obsługi czasu.źródło
user.createdAt && new Date(user.createdAt.nanoseconds)
. Date-fns nie pomoże w rozwiązaniu tego problemu, to po prostu przydatna biblioteka do wyświetlania daty, gdy już ją masz.firestore.FieldValue.serverTimestamp()
Jak wysłać datę do Firestore:
Jak to przeczytać ponownie:
Zasadniczo po
createdAt.toDate()
otrzymaniu obiektu JS Date.Cały czas tego używam!
Od: https://cloud.google.com/firestore/docs/manage-data/add-data
Spowoduje to utworzenie danych na podstawie daty systemowej użytkownika. Jeśli chcesz mieć pewność, że wszystko będzie przechowywane chronologicznie (bez błędów błędnych dat systemowych ustawionych przez system użytkowników) na twoim DB, powinieneś użyć znacznika czasu serwera. Data zostanie ustawiona za pomocą wewnętrznego systemu dat Firestore DB.
źródło
W przypadku identyfikatora dokumentu użytkownika, który ma
createdAt
ustawioną właściwość, spróbuj wykonać następujące czynności:Ważne jest, aby wywołać tę
.data()
metodę przed uzyskaniem dostępu do właściwości dokumentuPamiętaj, że jeśli uzyskasz dostęp
docRef.data().createdAt.toDate()
do użytkownika, dla którego właściwośćcreatedAt
nie jest ustawiona, otrzymaszTypeError: Cannot read property 'toDate' of undefined
Na wypadek gdyby w kolekcji znajdował się użytkownik, który nie ma
createdAt
zdefiniowanej właściwości. Należy wdrożyć logikę, aby sprawdzić, czy użytkownik macreatedAt
właściwość przed jej uzyskaniem. Możesz zrobić coś takiego:źródło
W przeszłości miałem problemy z właściwymi właściwościami zagnieżdżonego obiektu, które nie renderowały się poprawnie na listach, które
item.someProp
są uważane za obiekt, aleitem.someProp.someSubProp
nie rozwiążą się z wartościąsomeSubProp
initem.someProp
.Aby więc obejść ten problem, dlaczego nie utworzyć znacznika czasu dla zwykłego obiektu daty (lub pożądanego formatu wyświetlania) podczas tworzenia obiektu użytkownika?
źródło
DocumentSnapshot#data()
iDocumentSnapshot#get()
zaakceptować obiekt, który określa, jak obsługiwać jeszcze nie sfinalizowaneFieldValue.serverTimestamp()
wartości. Domyślnie, jeszcze nie sfinalizowany będzie po prostu zerowy. Użycie{ serverTimestamps: "estimate"}
spowoduje zmianę tych wartości zerowych na wartość szacunkową.