React-ファイヤーストアのタイムスタンプを表示する


10

反応アプリでファイアストアのタイムスタンプを表示する方法を理解しようとしています。

「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'を読み取れません

私はこの投稿この投稿この投稿、そしてこの投稿とそれらのような他の投稿を見てきました。これらはtoDate()が機能することを示唆しています。しかし、この拡張機能は私にエラーをスローします-toString拡張機能を試したときも含めます。

私がuser.createdAtを試すと、秒のあるオブジェクトが見つかったというエラーが表示されるため、firestoreに何かがあることを知っています。

以下のWaelmasの例を取り上げて、フィールドの出力を次のようにログに記録しようとしました。

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

}

これもマップステートメントに追加しようとしましたが、user.getが関数ではないというエラーが表示されました。

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

上記と同じエラーメッセージが生成されます。

ここに画像の説明を入力してください

次の試み

Firestoreで日付を記録し、それを読み取れるようにする方法を見つけようとしたときに発生した奇妙なことの1つは、送信ハンドラを1つのフォームで変更してこの式を使用することです。

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の子としては無効です(検出:Timestamp(seconds = 1576363035、nanoseconds = 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()
        })

前のフォームでは、新しいDate()の試みがデータベースに日付を記録するために機能しました。この例では、createdAtとcreatedAt1の両方のフィールドが同じデータベースエントリを生成します。

ここに画像の説明を入力してください

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

日付の値を出力しようとすると、最初のエラーは次のようなエラーを生成します。

オブジェクトはReactの子としては無効です(検出日:2019年12月15日21:33:32 GMT + 1100(オーストラリア東部夏時間))。子のコレクションをレンダリングするつもりなら、代わりに配列を使用してください

2番目は、次のエラーを生成します。

TypeError:未定義のプロパティ 'toDate'を読み取れません

私は次に何をしようかというアイデアに行き詰まっています。

私はこの投稿を見ましたが、これは次のことが役に立つかもしれないことを示唆しています:

                {item.createdAt1.Date.valueOf()}

そうではありません。それは言うエラーをレンダリングします:

TypeError:未定義のプロパティ 'Date'を読み取れません

この投稿は私と同じ問題を抱えているようですが、格納された日付値を表示する方法については触れていません。

この投稿は配列エラーメッセージで行き詰まっているようですが、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を使用していますが、これらのメソッドは、自分で作成したヘルパーメソッドのように見えます。

この値がフェッチされると、2つのプロパティ- _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:undefinedのプロパティ 'Timestamp'を読み取れません
Mel

私も試してみました:createdAt:TypeError例外::というエラーが返されますfirebase.firestore.fieldValue.serverTimestamp()fromDateから(新しいDate())は、未定義の読み取ることができませんプロパティ'fieldValueの'。
メル

これは私にとってはうまくいきませんでしたが、あなたがあなたが今まで使ってきたフォーマットを試そうと思ったきっかけを理解することに興味があります。ドキュメントに示されているものとは異なります。私があなたのために役立つ何かを発見した方法を学ぶことができれば、私にとってうまくいく方法を見つけることができるかもしれません(それらが誰にとっても同じではない理由がわかりません-しかし、試すための新しいアイデアが必要です)。助けてくれてありがとう。
Mel

私ができることは、次を使用して日付を保存することです(上記のように):createdAt:this.props.firebase.fieldValue.serverTimestamp()、
Mel


5

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()拡張機能を追加しようとしましたが、エラーメッセージは変更されません(これは単なるフォーマットであるはずです)
Mel

タイムスタンプの値をコンソールに記録できますか?それが正しいタイプのFirestoreタイムスタンプであることを確認するだけです。@メル
ワルマス

いいえ-コンソールログは機能しません-エラーも生成します-しかし、日付はテーブルのcreatedAtフィールドに記録されます-今、私はそれを読み返そうとしています。記録する日付を取得する方法を説明する投稿を作成しました(firebaseドキュメントではありません)。ここで、stackoverflow.com
Mel

あなたは公式ドキュメントで推奨されているアプローチとは異なるアプローチを取っているため、本当に何がうまくいかないのかわかりません。そもそも、タイムスタンプを作成してプッシュする方法に何らかの欠陥があるようです。タイムスタンプをFirestoreに保存するときは、回答の冒頭で述べた形式のオブジェクトである必要があります。このようにして、.toDate()で使用できる有効なタイムスタンプとして認識されます。Firestore.Timestamp.now()は、チェックアウトするための正しい形式のタイムスタンプを提供します。@メル
ワルマス

公式ドキュメントに従ってタイムスタンプを作成してみました。うまくいきませんでした。日付を記録する別の方法を見つけましたが、出力を読み返すことができません。とてもイライラします。とにかく助けてくれてありがとう。
Mel

2

つまり、firestoreは日付を秒とナノ秒のオブジェクトとして格納します。ユーザーが作成された時刻が必要な場合は、参照しuser.createdAt.nanosecondsます。これは、UNIXタイムスタンプを返します。

アプリに日付をどのように表示しますか?日付オブジェクトを取得したい場合は、タイムスタンプを日付コンストラクタに渡すことができますnew Date(user.createdAt.nanoseconds)。個人的には、時間を扱うためにdate-fnsライブラリを使用することを楽しんでいます。


ありがとう-私はこの提案を試みました。TypeError:undefinedのプロパティ 'nanoseconds'を読み取れません。あなたが今提案したライブラリを見てみましょう
Mel

createdAtをログに記録して共有してください。データの非同期の性質を考えると、おそらくそれだけで返す必要がありますuser.createdAt && new Date(user.createdAt.nanoseconds)。date-fnsはこの問題には役立ちません。日付を取得したら、日付を表示するための便利なライブラリにすぎません。
Josh Pittman、

createdAtは、ドロップダウンメニューの長いリストをログに記録します。Firestoreのフィールドに表示される日付を含むものを見つけることができません。最初の部分は次のとおりです:createdAt:ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto:FieldValueImplコンストラクタ:ƒServerTimestampFieldValueImpl()インスタンス:ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto:FieldValueImplコンストラクタ:ƒServerTimestampFieldValueImpl(Field:Impl {Field) FieldValue.serverTimestamp "}引数:(...)呼び出し元:(...)
Mel

タイムスタンプ関数を実際のタイムスタンプではなくデータベースにプッシュしたようです。タイムスタンプをどのように設定していますか?firestore.FieldValue.serverTimestamp()
Josh Pittman、

firestoreに表示されているエントリは、添付した写真です。これがエントリです:this.props.firebase.fieldValue.serverTimestamp()
Mel

2

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

ここに画像の説明を入力してください

これにより、ユーザーのシステム日付に基づいてデータが作成されます。すべてが時系列で(ユーザーのシステムによって設定された誤ったシステム日付のエラーなしで)DBに確実に保存される必要がある場合は、サーバーのタイムスタンプを使用する必要があります。日付は、Firestore DBの内部日付システムを使用して設定されます。

ここに画像の説明を入力してください


ありがとうございましたが、データベースに記録された日付を表示する方法が見つからないという問題を克服しようとしています。共有した種類のエラーが何度も発生します。
Mel

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

上記のように、ドキュメントフィールドのリクエストではdata()を使用しています。他のフィールドをレンダリングしなかった場合は、レンダリングされません。特定の問題は、レンダリングされないタイムスタンプにあります。私が行った試みの1つに、上で述べたように、toDate()拡張を使用する試みがあります。上で説明した理由により、機能しません。とにかくありがとうございました。
Mel

0

ネストされたオブジェクトプロパティitem.somePropが、オブジェクトと見なされるリストで適切にレンダリングされないという問題に過去に遭遇しましたがitem.someProp.someSubPropsomeSubPropin の値では解決しませんitem.someProp

それでは、問題を回避するために、ユーザーオブジェクトを作成するときに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()値の処理方法を指定するオブジェクトを受け入れることにも注意してください。デフォルトでは、まだファイナライズされていないものは単にnullになります。を使用{ serverTimestamps: "estimate"}すると、これらのnull値が推定値に変更されます。
samthecodingman

こんにちは-提案をありがとう。試してみたいのですが、よくわかりません。どうすれば実装できますか。この提案を思いつく際に適用する原則についての慣習はありますか?このアプローチに関する文献が見つかった場合は、あなたのアイデアがどのように機能するかを理解して、コードで試すことができるようにします。
Mel

何年にもわたってStackOverflowの他の質問を調べた後、私はそれを取り上げたので、特定のリソースはありません。
samthecodingman

共有いただきありがとうございます。今夜読む
Mel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.