KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

firebase-timestamp-cannot-render

firebase timestamp cannot render

why

単に2chなサービスを作ろうとして,NoSQLなfirestoreにはauto-incrementなidがないから(idはあるけどrandなhex),created_at のtimestampのdataをrenderの時のsortのindexにしようとした.

何をしているか

単純なFirestoreからの読み込みとDOM render.
useCollectionを使ってShow.jsを書いている

import firebase from 'firebase/app';
import {firestore} from '../Config/config';
const ref = firebase.firestore().collection('writings');

これでconfig.jsに書いてあるapikeyなどからこのprojectのwriting tableを持ってきて

import {useCollectionData} from 'react-firebase-hooks/firestore';

const Show = () => {
  const [values, loading, error,] = useCollectionData(
    ref, {idField: 'id'});
  if(loading) {
    return <div>Loading...</div>
  }
  if(error) {
    return <div>{`Error: ${error.message}`}</div>
  }
  console.log(values);

  return (
    <Row>
      <Col>
        {values.map(value => (
            <div key = {value.id}>
              <div>
                {++num}:名無しさん:{value.id}:2019.05.17
              </div>
              <div>
                {value.content}type:
              </div>
            </div>
        ))}
      </Col>
    </Row>

.........

これでuseCollectionDataを使ってvaluesにwritingsの配列を渡している.そしてrenderで value.idとvalue.contentを描画している.

これでconsoleを見ると,配列にid, content, そしてcreated_atが入っているのが見える.

f:id:kei_s_lifehack:20200521023938p:plain

ちょっと待っておちんちんナメナメってだれw

Error

timestamp

ここで問題はtimestampになる. consoleをよくみてみると

15:
content: "かえでのちんちん舐め舐め"
created_at: t
    nanoseconds: 786000000
    seconds: 1589720334
  __proto__: Object
  id: "zTBHecvjaaZOtt3kVmIt"

このようにcontentやidのように直接は入っていなくて,

tのobjのように入っているのがわかる.

このtはfirebase consoleをみると

f:id:kei_s_lifehack:20200521024506p:plain

timestampで入っている.timestampのtらしい.

int32とかで書かれている特殊なtype.?

よって単純に value.created_atで出力しても

react-dom.development.js:13413 
Uncaught Error: Objects are not valid as a React child (found: object with keys {seconds, nanoseconds}). 
If you meant to render a collection of children, use an array instead.

objと中身が見つかりました,objはrenderできませんってerrorが出る.

try01 .toDate

ここで公式Docの通りに

f:id:kei_s_lifehack:20200521025107p:plain

{value.created_at.toDate}

としても

typeError: Cannot read property 'toDate' of undefined

で読み込めないと出てしまう.()をつけても同様だ.

try02 .get() about milli second

stackoverflow.com

こちらのサイトでも基本的に.toDate使えと書いてある. new Dateのところはdate to tsの方.

qiita.com

これによると

Server側のTimestampはMicro secondだが,JS Dateはmilli second

microseconds = milliseconds * 1000 なのでtsの方が精確.

つまり細かいものから大まかなものにはできるはず.

そしてコードは

const timestamp = snapshot.get('created_at');
const date = timestamp.toDate(); // JS Date 型が欲しい場合

でかけと書いてある

{value.created_at.get().toDate()}

.get()を挟んでみたがダメだった.

try03 servertimestamp

次は

あるとしたらServerTimestampとTimestampの違いかもThinking face

Only after you have synced with Firestore and the data is fetched again, the prop will be changed from serverTimestamp → to Timestamp

stackoverflow.com

However, ... FieldValue.serverTimestamp() gives nothing of value.

とあるので同じコードで同じ症状だ.

Add.jsxで

created_at: firebase.firestore.FieldValue.serverTimestamp.now(),

で書いているからね....

serverTimestamp() itself does not contain any date information, and you can't convert it to a date.

と書いてある.convertできないの辛くね?

ただ前の方に

Only after you have synced with Firestore and the data is fetched again, the prop will be changed from serverTimestamp → to Timestamp

fetchするとtimestampになって.toDateできるよって書いてあった!!これか!!!

f:id:kei_s_lifehack:20200521034411p:plain

本物のtimestampはtではなく,timestampと出るらしい...

serverTimestamp fetchで調べてもserverTimestampを入れる方法しかでなかった

hさんにまた聞きなおそう...

e-words.jp

読み取りに行く,getと同じ処理らしいがどう書くんだろう....

04 firestoreのdata type listから

ここらへんの記事見ると、timestamp 受け取ったときに timestamp オブジェクトが Date に変換する関数をもっているみたいですね

qiita.com

Dateオブジェクトでクライアントのタイマー取得してもしょうがないというケースが多いと思います。サーバ時間をセットする時は下記を使います。

firebase.firestore.FieldValue.serverTimestamp()

私はサーバー(の?)時間をDBにセットしていたんだな

Firestoreから取得したドキュメントにセットされているタイムスタンプ型を扱うときはtoDate()でJSのDate型に変換します。

firebase.firestore().collection('users').doc('123').get().then(function(doc) {
    var timestamp = doc.data().timestamp.toDate();
}

これを真似て

{value.created_at.timestamp.toDate()}

で.timestampを挟んでみたが,どのみち

Show.jsx:31 Uncaught TypeError: Cannot read property 'toDate' of undefined

toDateはないとErrorが出てしまう

try 05 .second

ブログ読みました created_at.seconds で秒がとれそうですね

Show.jsx:31 Uncaught TypeError: Cannot read property 'seconds' of undefined

.t.secondsでも同じだった

new Date(value.created_at.seconds)

でも同じ

{(new Date(value.created_at)).toString()}

で少し進んだ!!!

俺みたいな中3でグロ見てる腐れ野郎、他に、いますかっていねーか、ははtype:Invalid Date

Invalid Dateと出る.

これで(new Date(...))の部分をなくすと

Show.jsx:31 Uncaught TypeError: Cannot read property 'toString' of undefined

となる.value.created_atにstringがない

やはり謎のtが問題だ!!!!

{values.map(value => { console.log(value.created_at); return ""; })}

でsecがでた.

created_atが一つundefになってた

{value.created_at ?                         
  (value.created_at.toDate().toString()) :  
  "NO DATE"                                 
}         

例外処理で解決多分しました,明日テストします

これで綺麗に2ch完成しました.みてくれた方々ほんとうにありがとうございました !

f:id:kei_s_lifehack:20200521050150p:plain