反应-显示Firestore时间戳

时间:2019-12-11 01:55:20

标签: javascript reactjs firebase google-cloud-firestore unix-timestamp

我正在尝试弄清如何在React应用中显示Firestore时间戳。

我有一个Firestore文档,其中包含一个名为createdAt的字段。

我正在尝试将其包含在输出列表中(此处提取相关位,以便您不必通读整个字段列表)。

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

它会产生与上述相同的错误消息。

enter image description here

下一个尝试

试图找到一种在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条目的形式如下:

enter image description here

我正在尝试在此组件中显示日期

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))。如果你想   渲染孩子的集合,请改用数组。       在Item中(位于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()
        })

在以前的形式中,新的Date()尝试在数据库中记录了一个日期,在本示例中,createdAt和createdAt1的两个字段都生成相同的数据库条目:

enter image description here

<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()显示日期的方法

6 个答案:

答案 0 :(得分:4)

从Firestore获取时间戳时,它们属于以下类型:

enter image description here

要将其转换为普通时间戳,可以使用.toDate()函数。

例如,对于如下文档:

enter image description here

我们可以使用类似的东西:

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

,输出将是:

2019-12-16T16:27:33.031Z

现在可以进一步处理该时间戳了,您可以将其转换为字符串,并根据需要使用regex对其进行修改。

例如:(我在这里使用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]);
});

将为您提供如下输出:

enter image description here

答案 1 :(得分:2)

因此,firestore将日期存储为具有秒和纳秒的对象。如果需要创建用户的时间,则可以引用user.createdAt.nanoseconds。这将返回unix时间戳。

您想如何在应用程序中显示日期?如果要获取日期对象,则可以将时间戳传递到日期构造器中,例如new Date(user.createdAt.nanoseconds)。我个人喜欢使用date-fns库来处理时间。

答案 2 :(得分:2)

如何将日期发送到Firestore:

('a, 'b) either

如何读回它:

--gpus all

基本上,当您执行docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]]. ERRO[0000] error waiting for container: context canceled 时,您会得到一个JS Date对象。

我一直这样使用它!

发件人:https://cloud.google.com/firestore/docs/manage-data/add-data

enter image description here

这将基于用户的系统日期创建数据。 如果需要确保将所有内容按时间顺序存储(不存在用户系统设置的错误的系统日期错误),则应使用服务器时间戳。该日期将使用您的Firestore DB内部日期系统进行设置。

enter image description here

答案 3 :(得分:2)

对于确实设置了createdAt属性的“用户”文档ID,请尝试以下操作:

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()方法很重要

请注意,如果访问未设置docRef.data().createdAt.toDate()属性的用户createdAt,则将获得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());
  }
})

答案 4 :(得分: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")}

对于我的示例时间戳,其表示为:

  

12/30/2019


请确保您使用的时间戳记已另存为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)显示错误的日期

答案 5 :(得分:0)

过去,我遇到过以下问题:嵌套对象属性无法在item.someProp被视为对象的列表中正确呈现,但是item.someProp.someSubProp不能用someSubProp的值来解决在item.someProp中。

因此,为了解决问题,为什么在创建用户对象时不将时间戳记评估为纯日期对象(或所需的显示格式)?

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