teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

2064閲覧

TypeScript 配列の中身がオブジェクトでのuseStateの使用について

hiroki88

総合スコア66

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/09/01 10:08

編集2021/09/01 10:13

0

0

【やりたいこと】
firestoreから取得したデータの一覧をuseStateを使用してstateに格納したい。

【行なっている事】

TypeScrit

1type account = { 2 firstName: string, 3 lastName: string, 4}[]; 5 6function list(): ReactElement { 7 const [account, setAccount] = useState<account>(); 8 const getAccountData = async() => { 9 const accountListTable = db.collection('accountList'); 10 await accountListTable.get() 11 .then((snapshot)=> { 12 snapshot.forEach((doc) => { 13 setAccount({...account, doc.data()}); 14 }); 15 }) 16 .catch((e)=> { 17 console.log(e); 18 }); 19 }; 20       getAccountData(); 21 22 return( 23 <div> 24 ... 25 </div> 26 ); 27}

【処理の流れ】
1.accountというstateがあります。
2.firestoreにてaccountListコレクションからアカウントの一覧を取得します。
doc.data()の中身は下記のようになっています。

TypeScript

1{ 2 firstName: '太郎', 3 lastName: '山田', 4}

3.doc.data()の値をaccountに格納したいです。
accountの中身は下記を想定しています。

TypeScript

1account = [ 2 { 3 firstName: '太郎', 4 lastName: '山田', 5 }, 6 { 7 firstName: '花子', 8 lastName: '佐藤', 9 }, 10 { 11 firstName: '一郎', 12 lastName: '鈴木', 13 }... 14];

【困っている事】

TypeScript

1setAccount({...account, doc.data()}); 2 3//エラー内容 4'{ doc: firebase.firestore.QueryDocumentSnapshot<firebase.firestore.DocumentData>; "": any; length?: number | undefined; toString?: (() => string) | undefined; toLocaleString?: (() => string) | undefined; ... 30 more ...; [Symbol.unscopables]?: (() => { ...; }) | undefined; }' の引数を型 'SetStateAction<account | undefined>' のパラメーターに割り当てることはできません。 5 オブジェクト リテラルは既知のプロパティのみ指定できます。'doc' は型 'account | ((prevState: account | undefined) => account | undefined)' に存在しません。ts(2345)

ここの箇所でエラーが発生してしまっています。
初心者なため随時調べて行っているのですが配列の中身がオブジェクトの値をstateに格納するやり方が
調べても中々見つからず、また型の宣言も合っているか心配です...。
もし分かる方がいらっしゃればご教授頂きたいです。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/09/01 12:44

直接のエラーは、Firebase は doc.data() の型なんて知らないので、自分で型を検査するかキャストする必要があります。 その他、いくつか問題がありますね。 ・レンダリングのたびに getAccountData を実行してますが、setAccount が呼ばれるたびにレンダリングされて getAccountData が呼ばれるので、無限ループになるはず。これを防ぐには useEffect を使います。 ・getAccountData の中で await と .then() や .catch() を両方使う必要はないのでは。 ・snapshot の各要素に対して setAccount するより、一回でまとめて setAccount する方が好ましいです。しかも、account の値はループ中には変わらないため、現在のコードだとたぶんおかしな値になるはず。 あと、これは余計なお世話だとは思いますが、型や関数コンポーネントの名前は先頭を大文字にする習慣があるので、account ではなく Account、list ではなく List の方が良いと思います。また、account という単数型の型名なのに配列になってるのは違和感があるので、たぶん Account 型は配列じゃない方が良い気がします。
hiroki88

2021/09/01 14:25

ご回答して頂きありがとうございます!! エラーの件かしこまりました、調べて行ってみたいと思います。 またその他についてもご指摘頂きましてありがとうございます! ・無限ループにならないようuseEffectを使用して実行したいと思います。 ・確かにawaitとthen(),catch()の併用はおかしかったです、直します! ・そこに関しては自分もループして値をセットするより1回でセットできないか調べていたのですが良い記事が見つからず...もう一度調べたいと思います。 ・自分一人で行う場合は命名規則が雑になりがちなので教えて頂いた事を徹底して書いていきたいと思います。大文字にする習慣がある事は知らなかったので教えて頂きありがとうございます。 本件と別の事まで確認して頂いてありがとうございました!! 大変勉強になります!!
hoshi-takanori

2021/09/01 19:40

上に書いたのは回答ではなく、あくまでヒントです。自分で考えることが大事だと思ってるので。私の回答が欲しければ、そう言ってもらえたらいつでも答えます。 あと、もう一点。 ・account の各項目には id があるはずなので、それも保持して、表示の際の key や、後で編集などする場合に利用すると良いでしょう。
hiroki88

2021/09/09 16:12

頂いたヒントを元に調べて行い、ついにエラーを無くすことができました! ご報告が出来ればと思います! ・本件のエラーであるfirebaseのdoc.data()の型付はキャストを行いDocumentData[]型だったものをTypeAliasのaccount[]型に変更しました。 ・無限ループを避けるためにuseEffectを使用する予定でしたが描画前にgetAccountData関数を呼びだしたかったので今回はuseLayoutEffectを使用しようと思います。ただ調べるとなるべくuseLayoutEffectではなくuseEffectを使用した方が良いという事だったので悩んでおります。 ・awaitとthen(),catch()の併用はおかしい箇所はawaitの使用のみでtry&catchでエラーは拾おうかと思います。 ・setAccountにはスプレッド構文を使用し一回でまとめてセットできるようにしました。
hoshi-takanori

2021/09/09 22:17 編集

ご報告ありがとうございます。useLayoutEffect は描画の直前に何かしたい (たぶんアニメーションとか?) 場合に使うもので、普通に非同期処理を行うだけなら useEffect で充分でしょうね。
hiroki88

2021/09/10 00:27

そうゆうことですね、useLayoutEffectとuseEffectの使い分けを意識していきたいと思います! ヒントを頂きありがとうございました。 ベストアンサーにさせて頂きたいので回答の方に何かコメントを頂いてもよろしいでしょうか?
guest

回答2

0

useStateの初期化がされていないと思います。
useState<account>([])

投稿2021/09/01 22:12

編集2021/09/01 22:28
tonakai_route

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroki88

2021/09/02 15:02

ご回答ありがとうございます!こちらも参考にして再度実装してみたいと思います!
hiroki88

2021/09/09 16:13

無事エラーが解決できました!初期化できていないご指摘は反映させて頂きました! ありがとうございます!
guest

0

ベストアンサー

とりあえず、自分だったらこう書くかなってのを貼っておきます。

tsx

1type Account = { 2 id: string, 3 lastName: string, 4 firstName: string, 5}; 6 7function AccountList() { 8 const [account, setAccount] = useState<Account[]>([]); 9 10 useEffect(() => { 11 console.log('get...'); // デバッグ用 12 13 const accountListTable = db.collection('accountList'); 14 accountListTable.get() 15 .then((snapshot) => { 16 console.log(`${snapshot.docs.length} accounts`); // デバッグ用 17 18 const result: any[] = []; 19 snapshot.forEach((doc) => { 20 const account = { 21 id: doc.id, 22 lastName: doc.data().lastName ?? "", 23 firstName: doc.data().firstName ?? "", 24 }; 25 console.log(account); // デバッグ用 26 result.push(account); 27 }); 28 setAccount(result); 29 30 // または、次の一行。 31 // setAccount(snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }) as Account)); 32 }) 33 .catch((e) => { 34 console.log(e); 35 }); 36 }, []); 37 38 return ( 39 <> 40 <ul> 41 {account.map(each => <li key={each.id}>{each.lastName} {each.firstName}</li>)} 42 </ul> 43 </> 44 ); 45}

投稿2021/09/10 02:37

hoshi-takanori

総合スコア7903

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroki88

2021/09/10 02:45

ありがとうございます!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問