React - 显示 Firestore 时间戳
Posted
技术标签:
【中文标题】React - 显示 Firestore 时间戳【英文标题】:React - display a firestore timestamp 【发布时间】:2020-04-04 06:24:49 【问题描述】:我正在尝试弄清楚如何在 react 应用中显示 firestore 时间戳。
我有一个带有名为 createdAt 的字段的 firestore 文档。
我正在尝试将其包含在输出列表中(在此处提取相关位,这样您就不必通读整个字段列表)。
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()
唯一不会呈现的属性是日期。
上述每一次尝试都会产生一个错误,上面写着:
TypeError: 无法读取未定义的属性“toDate”
我见过this post、this post、this post、this post 和其他类似的,这表明 toDate() 应该可以工作。但是 - 这个扩展对我来说是一个错误 - 包括当我尝试 toString 扩展时。
我知道它知道 firestore 中有东西,因为当我尝试 user.createdAt 时,我收到一条错误消息,说它找到了一个包含秒数的对象。
以下面的Waelmas为例,我尝试将字段的输出记录为:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc)
console.log(doc.data().createdAt.toDate());
我也尝试将此添加到我的 map 语句中,但收到一条错误消息,提示 user.get 不是函数。
user.get().then(function(doc)
console.log(doc.data().createdAt.toDate());
)
它会生成与上面相同的错误消息。
下一次尝试
在试图找到一种方法在 Firestore 中记录日期以允许我读取它时出现了一件奇怪的事情,那就是当我以一种形式更改我的提交处理程序以使用此公式时:
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();
;
这可以在数据库中记录日期。
firestore 条目的形式如下所示:
我正在尝试在此组件中显示日期:
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);
当我尝试回读时 - 使用:
item.email
错误信息如下:
错误:对象作为 React 子对象无效(发现: 时间戳(秒=1576363035,纳秒=52000000))。如果你打算 渲染一组孩子,请改用数组。 在项目中(在 UserIndex.jsx:74)
当我尝试使用这些尝试时:
item.createdAt
item.createdAt.toDate()
item.createdAt.toDate().toISOString()
我收到一条错误消息:
TypeError: 无法读取未定义的属性“toDate”
基于在其他字段中回读记录在同一文档中的条目的能力,我希望这些条目中的任何一个都能产生输出——即使它没有按照我想要的方式格式化。这不会发生。
下一次尝试
以 Waelmas 为例,我尝试按照说明进行操作,但第一步是我们没有得到相同的响应。在 Walemas 获得基于 .toDate() 扩展名的输出的地方,我收到一条错误消息,指出 toDate() 不是函数。
与 Firebase 文档一致,我尝试过:
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());
)
这会产生一串语法错误,我找不到解决方法。
下一次尝试
然后我尝试制作一个新表单,看看是否可以在没有用户表单的身份验证方面进行探索。
我有一个表单输入为:
this.props.firebase.db.collection("insights").add(
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
)
在之前的表单中,new Date() 尝试在数据库中记录日期,在此示例中,createdAt 和 createdAt1 的两个字段都生成相同的数据库条目:
<div>item.createdAt.toDate()</div>
<div>item.createdAt.toDate()</div>
当我尝试输出日期的值时,第一个会产生一个错误,上面写着:
对象作为 React 子级无效(发现时间:2019 年 12 月 15 日星期日 21:33:32 GMT+1100(澳大利亚东部夏令时间))。如果你打算 渲染一组孩子,使用数组代替
第二个产生错误说:
TypeError: 无法读取未定义的属性“toDate”
我不知道下一步该尝试什么。
我看到this post 表明以下内容可能会做一些有用的事情:
item.createdAt1.Date.valueOf()
它没有。它呈现一个错误,上面写着:
TypeError: 无法读取未定义的属性“日期”
这个post 似乎遇到了和我一样的麻烦,但没有详细说明他们如何设法显示他们存储的日期值。
这个post 似乎卡在数组错误消息中,但似乎已经弄清楚如何使用 createdAt.toDate() 显示日期
【问题讨论】:
【参考方案1】:经过一番讨论,我们发现 OPs 用户对象中的时间戳可以这样渲染:
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")
我在一个虚拟 React 项目中重新创建了您的示例,并收到了与预期相同的错误。
错误:对象作为 React 子级无效
我能够使用以下方法正确渲染它,这也应该适用于您:
new Date(user.createdAt._seconds * 1000).toLocaleDateString("en-US")
对于我的示例时间戳,呈现为:
2019 年 12 月 30 日
确保您使用的是保存到 Firestore 的时间戳:
createdAt: this.props.firebase.Timestamp.fromDate(new Date())
注意:这是假设您的 firebase.firestore()
实例位于 this.props.firebase
。在其他示例中,您使用 this.props.firebase,但这些方法看起来像您自己创建的辅助方法。
当这个值被获取时,它将是一个具有两个属性的对象——_seconds
和_nanoseconds
。
请务必包含下划线。如果用createdAt.seconds
不行,一定是createdAt._seconds
。
我尝试过的其他事情:
user.createdAt.toDate()
抛出 toDate() is not a function
。
user.createdAt
抛出 Error: Objects are not valid as a React child
new Date(user.createdAt._nanoseconds)
呈现错误的日期
【讨论】:
嗨 - 感谢您的建议。我试过这个并得到一个错误,上面写着:TypeError: Cannot read property 'Timestamp' of undefined 我也试过了:createdAt: firebase.firestore.fieldValue.serverTimestamp().fromDate(new Date()),它返回一个错误,上面写着:TypeError: Cannot read property 'fieldValue' of undefined 虽然这对我不起作用,但我很想了解您是如何考虑尝试使用您使用的格式的。它不像文档中显示的那样。如果我能了解你是如何发现适合你的东西的,它可能会让我找到一种适合我的方法(我不明白为什么这些对每个人都不一样——但我需要新的想法来尝试)。再次感谢您提供帮助。 我能做的是保存一个日期(如上所示),使用:createdAt: this.props.firebase.fieldValue.serverTimestamp(), 让我们continue this discussion in chat。【参考方案2】:当您从 Firestore 获取时间戳时,它们属于以下类型:
要将其转换为普通时间戳,您可以使用 .toDate() 函数。
例如,对于如下文档:
我们可以使用类似的东西:
db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc)
console.log(doc.data().[FIELD].toDate());
);
输出如下:
2019-12-16T16:27:33.031Z
现在要进一步处理该时间戳,您可以将其转换为字符串并使用正则表达式根据您的需要进行修改。
例如:(我这里使用的是 Node.js)
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]);
);
会给你这样的输出:
【讨论】:
谢谢你的例子。我的尝试有相同的结构。它可以返回文档中的所有字符串值,但不返回日期。相反,它会生成我在上面发布的消息的错误。这没有任何意义。我尝试添加 toISOString() 扩展,但它不会更改错误消息(应该只是格式化) 你能在控制台中记录时间戳的值吗?只是为了确认它是正确类型的 Firestore 时间戳。 @梅尔 否 - 控制台日志不起作用 - 它也会产生错误 - 但日期会记录在表的 createdAt 字段中 - 现在我只是想读回它。我在这里创建了一个帖子,解释了我如何获得记录日期(不是根据 firebase 文档):***.com/questions/59257755/… 由于您采用的方法与官方文档推荐的方法不同,我不确定真正出了什么问题。似乎您首先创建和推送时间戳的方式存在某种错误。当您将时间戳存储到 Firestore 时,它必须是我在回答开头提到的格式的对象。这样,它就会被识别为有效的时间戳,然后可以与 .toDate() 一起使用。 Firestore.Timestamp.now() 会给你一个正确格式的时间戳来检查它。 @梅尔 我尝试按照官方文档创建时间戳。我无法让它工作。我偶然发现了另一种记录日期的方法,现在无法读回输出!太令人沮丧了。无论如何感谢您的帮助。【参考方案3】:因此,firestore 将日期存储为具有秒和纳秒的对象。如果您想要创建用户的时间,那么您将引用user.createdAt.nanoseconds
。这将返回一个 unix 时间戳。
您希望如何在应用中显示日期?如果您想获取日期对象,则可以将时间戳传递给日期构造函数,如new Date(user.createdAt.nanoseconds)
。我个人喜欢使用date-fns 库来处理时间。
【讨论】:
谢谢 - 我试过这个建议。它返回一个错误,上面写着:TypeError:无法读取未定义的属性“纳秒”。我现在看看你建议的库 你能登录 createdAt 并分享一下吗?鉴于数据的异步性质,您可能只需要像user.createdAt && new Date(user.createdAt.nanoseconds)
那样返回它。 Date-fns 无法解决这个问题,它只是一个方便的库,一旦你拥有它就可以显示日期。
createdAt 记录一长串下拉菜单。我找不到包含在 firestore 字段中显示的日期的文件。第一部分是: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto: FieldValueImpl 构造函数: ƒ ServerTimestampFieldValueImpl() 实例: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto: FieldValueImpl 构造函数: ƒ ServerTimestampFieldValueImpl() 实例:ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" 参数:(...) 调用者:(...)
听起来您已经将时间戳功能推送到数据库,而不是实际的时间戳。你是如何设置时间戳的? firestore.FieldValue.serverTimestamp()
firestore 中显示的条目是我附加的照片。这是条目:this.props.firebase.fieldValue.serverTimestamp()【参考方案4】:
如何将日期发送到 Firestore:
import firebase from 'firebase/app';
// ..........
// someObject is the object you're saving to your Firestore.
someObject.createdAt: firebase.firestore.Timestamp.fromDate(new Date())
如何回读:
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>
);
基本上,当您执行createdAt.toDate()
时,您会得到一个 JS Date 对象。
我一直都是这样用的!
发件人:https://cloud.google.com/firestore/docs/manage-data/add-data
这将根据用户的系统日期创建数据。 如果您需要确保所有内容都将按时间顺序存储(没有任何由您的用户系统设置的错误系统日期错误)在您的数据库中,您应该使用服务器时间戳。日期将使用您的 Firestore DB 内部日期系统设置。
【讨论】:
谢谢你,但我要克服的麻烦是我找不到显示数据库中记录的日期的方法。我不断收到我分享的错误。【参考方案5】:如果用户的文档 ID 具有 createdAt
属性集,请尝试以下操作:
const docRef = db.collection("users").doc("[docID]");
docRef.get().then(function(docRef)
if (docRef.exists)
console.log("user created at:", docRef.data().createdAt.toDate());
)
在访问文档的属性之前调用.data()
方法很重要
请注意,如果您访问未设置createdAt
属性的用户的docRef.data().createdAt.toDate()
,您将获得TypeError: Cannot read property 'toDate' of undefined
因此,如果您的集合中有任何用户没有定义 createdAt
属性。您应该实现一个逻辑来检查用户是否拥有createdAt
属性,然后再获取它。你可以这样做:
//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());
)
【讨论】:
如您在上面看到的,我确实在对文档字段的请求中使用了 data()。如果我不这样做,其他字段将不会呈现。具体问题是时间戳,它不会呈现。我在上面进行的尝试之一包括使用 toDate() 扩展的尝试。它不起作用 - 由于上述原因。无论如何感谢您的宝贵时间。【参考方案6】:过去我遇到过嵌套对象属性无法在 item.someProp
被视为对象的列表中正确呈现的问题,但 item.someProp.someSubProp
无法使用 item.someProp
中的 someSubProp
值解决。
所以要绕过这个问题,为什么不在创建用户对象时将 Timestamp 评估为普通日期对象(或所需的显示格式)?
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,
);
);
【讨论】:
另外值得注意的是,DocumentSnapshot#data()
和 DocumentSnapshot#get()
都接受一个对象,该对象指定如何处理尚未最终确定的 FieldValue.serverTimestamp()
值。默认情况下,尚未最终确定的将简单地为空。使用 serverTimestamps: "estimate"
会将这些空值更改为估计值。
嗨 - 感谢您的建议。我想尝试一下,但我不明白 - 或者我如何尝试实现它。您在提出此建议时应用的原则是否有约定。如果我能找到有关该方法的文献,我会尝试弄清楚你的想法是如何工作的,以便我可以在我的代码中尝试它。
我没有找到任何特定的资源,因为我是在多年来查看other *** questions 后才找到的。以上是关于React - 显示 Firestore 时间戳的主要内容,如果未能解决你的问题,请参考以下文章
当聊天线程有未读消息时如何显示徽章React JS,Firestore
如何在 Kotlin 中将 Firestore 日期/时间戳转换为日期?
将图像从 Firebase 存储链接到 Firestore 文档并在 React Native 中显示它们
渲染从 Firebase Firestore 映射的 React 组件
我正在尝试上传图片,但图片未添加到云 Firestore,它已上传到 Firebase 存储但未显示在 React 应用程序中