Open34

LL

chgnrchgnr

[Javascript]

const function = () => {
  for (const doc in docs) {
    if (){
      return
    }
  }
}

for 文から脱出したい時に間違って、return としていて、function から出てしまっていた。
for 文を終わらせたい時は break、for 文のループをスキップしたいときは continueを使う。

chgnrchgnr

[Javascript]
async のエラーハンドリング。
asyncをつけると 「Promise」を返してくれるので、呼び出し側に catch とか付ければ見た目スッキリする。

// 以前
const func = async () => {
  let url
    try {
      ~~~~~~
    } catch (err) {
      ~~~~~~
    }
}
func()
// スッキリ
const func = async () => {
 }

func()
  .then()
  .catch()

参考:https://zenn.dev/yukiota/articles/cb53ea21d7cf3994861a

chgnrchgnr

[HTML]
input type="number" で、 step=1 を指定すると、整数のみの validation が設定される。

<input
  type="number"
  step="1"
/>
chgnrchgnr

[Typescript]
input type="number" としても、型は number にならない。そのため、e.target.value は string型となってしまう。この場合、 Number()で括ることで、number型にする。

const num = Number(e.target.value)
chgnrchgnr

[Javascript]
オブジェクトのキーを変数にしたい場合 [] をつける
{key: value} とすると key: "太郎"となってしまう。

const key = name
const value = "太郎"
const obj = { [key]: value } 

console.log(obj) // { name: "太郎" }
chgnrchgnr

[React]

// これしか知らなかった。
<h1>{user.name ? username : "No name"}</h1>

// user が true なら、user.nameを返す。
<h1>{user && user.name}</h1>

// さらにスッキリ
<h1>{user?.name}</h1>

// user.name が true なら、user.nameを返して、falseなら || の隣を返す。超便利。
<h1>{user.name || "No name"}</h1>

引用:
javascriptでは空文字や数字の0はfalse評価されてしまう...... 知らなかった。

参考:
https://zenn.dev/ryuji_ito/articles/9c2ab83bb2e962

chgnrchgnr

[React]

<input
  type="text"
  name="title"
  value={cardTitle}
  onChange={(e)=>setCardTitle(e.target.value)}
/>

input フォームで出たエラー。
入力内容を onChangeで拾って、setStateで value にセットしていた。「uncontrolled から controlled に変わっちゃってるよ」というwarning.

下記のように初期値を与えたら直った。

// before
  const [cardTitle, setCardTitle] = useState() 

// after
  const [cardTitle, setCardTitle] = useState('')

初期値を与えていなかったので、 <input value={undefined}> となってしまって(uncontrolled)、後から setState の値をぶち込もうとして(controlled)、warningが出たのかも?

chgnrchgnr

[Javascript]
posts(配列) の真偽値判定の時、posts = [] (配列が空)でも true となってしまうので、posts.length が 0かどうかで判定する。

chgnrchgnr

[Javascript]

Object.keys(arr[0]).map(key => {
  if (key == "tableId") return
    console.log(key)
  })
}

map で スキップしたい時に continue は使えなかった。 省きたい条件をif文で書いて return させれば解決した。

chgnrchgnr

[React]
内容:button の onClick時、setState させてるにもかかわらず、stateが更新されなかった。
原因:useEffectで毎回初期値をsetStateしていたんだけど、useEffectの第二引数[]を指定していなくて、毎回useEffect されていた模様。

// before
useEffect(()=> {
  setPosts(props.posts)
})

// after
useEffect(()=> {
  setPosts(props.posts)
},[])

chgnrchgnr

🔥[React]
内容:props で持ってきたデータを state 管理&mapで回したいんだけど、よく分からず
原因:不明🤮🤮🤮🤮🤮🤮🤮

// これはイケる。けど、stateで管理したい(postsを追加・削除するので)
const CardList = (props) => {
  const posts = props.posts

  return (
    <div>
      {posts && posts.map()}
    </div>
  )
}

// これはダメ。初期値が入らない。
const CardList = (props) => {
  [posts, setPosts] = useState(props.posts)

  return (
    <div>
      {posts && posts.map()}
    </div>
  )
}

// これもだめ。
const CardList = (props) => {
  [posts, setPosts] = useState()
  useEffect(()=> {
    setPosts(props.posts)  
  },[])

  return (
    <div>
      {posts && posts.map()}
    </div>
  )
}
chgnrchgnr

[Git]
ブランチの削除の仕方

// ローカル側のブランチ削除
git branch --delete [branch name]

// -d でも可
git branch -d [branch name]

// リモート側のブランチ削除
git push origin :[branch name]
chgnrchgnr

[Nextjs][Typescript]

type Props = {
  posts: Posts[];
  user: user;
}

// NextPage に generics で Props型を指定
const Page: NextPage<Props> = (props) => {
  ~~
  ~~
}

// getStaticProps の 返り値の型をチェックできる
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
  ~~ 
  ~~
  return {
    props: {
      posts,
      user,
    }
  }
}

chgnrchgnr

[React][Typescript]
関数コンポーネント(Function Component)の props の型の指定方法

type Props = {
  body: string;
}

// React.FC を指定して、 generics をつける
const Post: React.FC<Props> = (body) => {
}
chgnrchgnr

[Typescript]

// rows, cols は number なので、下記はダメ(stringになっている)
<textarea
  rows="4"
  cols="40"
/>

// {数値} としてあげる
<textarea
  rows={4}
  cols={40}
/>
chgnrchgnr

[React]
Escキーで Modalを閉じるケース

  1. document.addEventListenerで keydownイベントが発生するときに通知を受け取る keyPresslistener を登録
  2. useCallbackで Escapeキーを押した時の関数をメモ化(キャッシュ的な)
  3. Modal のアンマウント時に、登録したリスナーを削除(removeEventListener
  4. useEffectの第二引数に keyPress を登録しておくことで、Modalアンマウント時の clean upを呼べる
  5. useCallbackの第二引数にsetShowModal, showModalを指定することで、これらの変数が変わるごとに再実行(setShowModalを記載する理由がよく分からん)
const keyPress = useCallback(
  e => {
    if (e.key === 'Escape ' &&  showModal) {
      setShowModal(false)
    }
  },
  [setShowModal, showModal] // ここの変数が変わったら再実行
);
 
useEffect(() => {
  document.addEventListner('keydown', keyPress)
  return () => document.removeEventListener('keydown', keyPress) // アンマウント時の処理
},[keyPress]) // ここの変数が変わったら再実行

参考:https://sbfl.net/blog/2019/11/12/react-hooks-introduction/
参考:https://www.youtube.com/watch?v=d3aI1Dt0Z50

chgnrchgnr

[CSS]
flex-box使用時、カードを2列表記から1列表記にしようと思って flex-wrap: nowrapを指定したら、それぞれのカードが詰まって配置されてしまった(width: 40%的なものが無視された)。

正しくは、flex-wrap: wrap を指定して、width: 100% とする。

chgnrchgnr

[Firestore]
Firestore の Timestamp データを基に、dayjs.extend(relativeTime) を使って、投稿時間と現在時刻の差を出したかった。

Timestampデータは {nanoseconds: 431000000, seconds: 1612952177}といったオブジェクトであり、dayjsの引数は JS の Date型 である必要があった。

そのため、toDate() を使うことで解決

const date = createdAt.toDate() // createdAt は Firestore の Timestamp

~~~
~~~

<time dateTime={date}>
  {dayjs(date).fromNow()}
</time>
chgnrchgnr

[Firestore]
配列に要素を追加したかった。{merge: true}では上書きされるため、arrayUnionを使う。

// 上書きされるケース
firebase.firestore().collection("companies").doc(symbol)
  .set({events: eventName}, {merge: true});

// 配列に追加
firebase.firestore().collection("companies").doc(symbol)
  .update({events: firebase.firestore.FieldValue.arrayUnion(eventName) });
chgnrchgnr

[HTML]
button の onClick を使って関数を実行すると、ページ遷移される。これは、button のtype が デフォルトで submit であったため。 button 属性にすれば、ページ遷移されない。

// レンダリングされる(デフォルトで type="submit"のため)
<button onClick={()=>func()} >完了</button>

// レンダリングされない
<button type="button" onClick={()=>func()} >完了</button>

// func()の中で、 e.preventDefault() としても、ページ遷移を防げる。
chgnrchgnr

[GAS]
Google App Script を使って、Google Adsense の結果を LINE に通知しようと思った時に、message: may not be emptyエラーが出た。message にはきちんとデータが入っていたが...🤔

function main() {
  var text = lastMonth + "月のadsense成果発表です🎉\n"
  + "\nページビュー数\t" + report[0][0] + "回"
  + "\nCTR:クリック率\t" + report[0][1]*100 + "%"
  + "\n\n💰今月の収益💰\t" + report[0][2] + "円"

  SendToLine(text);
}

function SendToLine(message) {
  var token = "XXXXXXXXXXXXXXXXXXXXXXXXX";
  var op = 
    {
      "method": "post",
      "Content-Type": "application/x-www-form-urlencoded",
      "payload": "message=" + message,
      "headers": {"Authorization": "Bearer " + token}
    };
  var res = UrlFetchApp.fetch("https://notify-api.line.me/api/notify", op);
 }

原因は、CTRクリック率を示すところで、「半角の%」が入っていたため。

chgnrchgnr

[Firestore]
セキュリティルールのテスト

// 1. Packege json に下記を記載
"test": "firebase emulators:exec --only firestore 'jest'"

// 2. 実行
npm run test
chgnrchgnr

[Firestore]
セキュリティールールで急にエラー。

match の インデントに騙されて、無駄なブラケットがついていた。
このせいで、エラーになって動かないだけでなく、動くけどテスト結果がおかしい(FailsがSucceedsしたり)ことになった。

chgnrchgnr

Firestoreのセキュリティールールのテスト中、急に結果がおかしくなった。認証(isAuthenticated)が全てFailsに変わった。

セキュリティールールの中で、「tags は無くてもいい or tagsはマップ型」とすべきところの記述がおかしかった。

// ! の位置がおかしい
&& ((!'tags' in request.resource.data) || (request.resource.data.tags is map))

// 正しくはこっち
&& (!('tags' in request.resource.data) || (request.resource.data.tags is map))
chgnrchgnr

[firestore]
オブジェクトは map, 配列は list

// オブジェクト
&& (!('tags' in request.resource.data) || (request.resource.data.tags is map))

// 配列
&& (!('Etags' in request.resource.data) || (request.resource.data.tags is list))
chgnrchgnr

[Firestore]
下記のエラーがでた。request.resouce.data.name の data をつけ忘れてた。

FirebaseError: 7 PERMISSION_DENIED: 
Property name is undefined on object. for 'create' @ L117
// NG
&& request.resource.name is string

// OK
&& request.resource.data.name is string
chgnrchgnr

[React]
mapで配列を展開した時に要素が表示されなかった。() で囲むべきところを {} で囲んでいた。

// NG
{members.map((member, i) => { // 👈
  <div>{member.name}</div>
})}

// OK
{members.map((member, i) => ( 
  <div>{member.name}</div>
))}
chgnrchgnr

[Firebase auth]
本番環境で firebase auth の サインインメソッドが使えなかった。
👉 firebase console => auth で、承認済みドメインに追加すればOK。

chgnrchgnr

[React]
map で展開した input要素 を delete した時に、DOM上でのデータ反映がうまくいかなかった。

原因:
key を todo-${i} のように、インデックス展開していたため。
要素が並び変わる可能性がある場合、インデックスをkeyにすると不都合が起きるとのこと(公式サイトより)。

対策:
一意なキーを振るために、 key = Date.now() と設定した。

https://ja.reactjs.org/docs/lists-and-keys.html

chgnrchgnr

Firebase cloud functions

内容:エラー探しに時間を要した。

  1. エラー箇所が見つけられなかった(575行目???ってなった)
  2. 名付けた覚えのない _b という変数が見つけられなかった

結果:
typescript のコンパイル後のファイル(出力先 lib 以下の js ファイル)を見れば、正しいエラー箇所がわかる

chgnrchgnr

Firebase extensions (stripe/firestore-stripe-payments@0.2.2)

内容:
Stripe の拡張機能のアップデート後、webhook エラー発生。

原因:

  1. 今回から Secret Manager に対応されたが、そこで設定するトークンをミスった(dev と prod のトークンを逆にしていた)
  2. webhook の指定URLがちゃっかり変わっていたことに気がつかなかった。
// before
https://asia-northeast1-XXXXX.cloudfunctions.net/ext-firestore-stripe-🔥[subscriptions]🔥-handleWebhookEvents

// after
https://asia-northeast1-XXXXX.cloudfunctions.net/ext-firestore-stripe-🔥[payments]🔥-handleWebhookEvents