はじめに
「Promiseってなんですか?」って職場の後輩に聞かれたら「お金貸してくれるところだよ!!」ってぐらいにしか答えられなさそうな理解度だったので、このあたり色々調べながら実装して無事爆死したことをメモします。
問題
export const getAllTodos = async () => {
const { data, error } = await supabase.from("study-record").select("*")
if (error) {
console.log("getAllTodos error: ", error)
return []
}
return data
上記のような処理で、呼び出し側では
const [records, setRecords] = useState([])
useEffect(() => {
const todos = getAllTodos()
setRecords(todos)
}, [])
// records.map(() => {})...などの配列処理を下のほうで実装してたりする
のようにしたら、WebのコンソールでUncaught TypeError: records.map is not a functionとエラーがでました。
???
「.mapなんて関数はないよ!」とJavaScriptに怒られてしまいました。
おかしいと思ったら、todosの型がconst todos: Promise<any[]>となっていました。
getAllTodos()でDBレコードの配列データが返ってくると思ってrecordsの初期値はuseStateで空配列をセットしていたのに、Promise型が返ってきててこれをセットしたせいで型エラーになっちゃったみたいですね。
Promise型から実データを抽出するには、asyncにした関数を呼び時に、awaitをつけてあげればPromiseが剥がれて実データが取れると気づきました。
※こちらの記事で、Promiseとかawaitについて学びました
useEffect(() => {
const todos = await getAllTodos() // async関数であるgetAllTodos()のあたまにawaitをくっつける
setRecords(todos)
}, [])
これで解決!、、、とはならずに、画面に思いっきりエラーが。
[PARSE_ERROR] await is only allowed within async functions and at the top levels of modules
await を使うには、async 関数内じゃないとだめだよと、、
なんか卵が先か、鶏が先か、みたいな話で混乱してきました(違う)。。
解決方法
別の記事を読んで、useEffect内でawaitを使いたい場合は、async関数をuseEffect内に書いてそれを呼び出せばいいだけ、と学んだので、以下のように実装。
useEffect(() => {
// useEffect内に、async関数を書いてあげる
const fethchTodos = async () => {
const todos = await getAllTodos()
setRecords(todos)
}
// ↑で書いた処理を呼び出し
fethchTodos()
}, [])
これでうまく表示できました!
おわりに
これで多少は迷える後輩にPromiseについて教えてあげられそうです。
後輩なんかいないんですけどね。
