Closed22

フロントエンド初学者がNext.js + Typescript + FireStore + Material-UI + SSGでサイト作るまでのメモ

takeuma0825takeuma0825

Firestoreから取得したデータを型変換する仕組みがFirestore側に標準である。
firebase. firestore. FirestoreDataConverter < T >

export type Word = {
  description: string;
  word: string;
};

// コンバート情報の定義
export const wordConverter = {
  toFirestore(word: Word): firebase.firestore.DocumentData {
    return {
      description: word.description,
      word: word.word,
    };
  },
  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot,
    options: firebase.firestore.SnapshotOptions
  ): Word {
    const data = snapshot.data(options)!;
    return {
      description: data.description,
      word: data.word,
    };
  },
};

const wordList: Word[] = [];
await db.collection("words")
  .withConverter(wordConverter) // コンバート指定
  .get()
  .then((ss) => {
    ss.forEach((s) => {
      wordList.push(s.data());
    });
  });
takeuma0825takeuma0825

Firestoreから取得した値でフィールドがない場合、コンバート時にはundefinedになる。
getServerSidePropsの戻り値はシリアライズできることが条件になっているため、コンバート時にundefinedチェックを行う。

// 型エイリアス
export type Word = {
  alphabet?: string;
  description: string;
  word: string;
};

//  コンバート処理
export const wordConverter = {
  toFirestore(word: Word): firebase.firestore.DocumentData {
    return {
      alphabet: word.alphabet === undefined ? null : word.alphabet,
      description: word.description,
      word: word.word,
    };
  },
  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot,
    options: firebase.firestore.SnapshotOptions
  ): Word {
    const data = snapshot.data(options)!;
    return {
      alphabet: data.alphabet === undefined ? null : data.alphabet,
      description: data.description,
      word: data.word,
    };
  },
};
takeuma0825takeuma0825

Material-UIをSSRで使おうとしたらエラーが出た。

Warning: Prop `className` did not match. Server: "MuiTypography-root makeStyles-text-35 MuiTypography-body1" Client: "MuiTypography-root makeStyles-text-1 MuiTypography-body1"

Server側とClient側でCSSが共有化できていないため発生したようだ。

Material-UIをSSRで使うには設定が必要。
Server Rendering

takeuma0825takeuma0825

改行コードが入っているテキストを改行したまま表示する方法
https://qiita.com/ktnydi/items/c7027f9528df729a1e2f

takeuma0825takeuma0825

CSS(@material-ui/core/styles)でwhiteSpace: "pre-wap"したが、改行されない。
スタイルシートは正しくかけているように見えるけど、何か間違えているのか。

takeuma0825takeuma0825

Firestoreから取得した値を確認したらエスケープ処理されていた。
"年間経常収益\\nTEST"

実装箇所で、replaceしてあげたら正しく改行された。

{word.replace("\\\n", "\n")}

takeuma0825takeuma0825

String.prototype.replace()は1つ目しか対象にならない。

const p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?';

console.log(p.replace('dog', 'monkey'));
// expected output: "The quick brown fox jumps over the lazy monkey. If the dog reacted, was it really lazy?"

String.protptype.replaceAll()はすべて対象となるようだが、エラーで使えない。

Property 'replaceAll' does not exist on type 'string'. Do you need to change your target library? Try changing the `lib` compiler option to 'esnext' or later.ts(2550)
takeuma0825takeuma0825

String.prototype.replaceAll()はECMA-262で使用可能となるようだ。
https://tc39.es/ecma262/#sec-string.prototype.replaceall

tsconfig.jsonのlibを変更すれば対応できるのか?

  "compilerOptions": {
    "lib": ["dom", "es2017"],
    "module": "esnext",
  },

各ブラウザバージョンも比較的最新版でないと利用できないAPIのため、別の方法が良さそう。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll#browser_compatibility

takeuma0825takeuma0825

Firestoreで検索かつソートを行う際に異なるフィールドを指定する場合は、複合インデックスを作成する必要がある。

    await db
      .collection("words")
      .withConverter(wordConverter) //  objectコンバータで変換して型安全に利用する。
      .where("syllabary", "==", char)
      .orderBy("word")

takeuma0825takeuma0825

firebase deploy時にエラーが発生。
無料プランだからNGとのこと。

Error: Server Error. getaddrinfo EAI_AGAIN firebaserules.googleapis.com

https://blog.nagatech.work/post/twitterbot/361

SSGだからAPI実行はされないと思っていたが何らかの設定不備?

takeuma0825takeuma0825

しばらくして再度firebase deployしたら今度は成功。
特に変更したことはなく理由は定かではない。

このスクラップは2021/03/07にクローズされました