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

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

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

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

TypeScript

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

React.js

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

Q&A

解決済

1回答

499閲覧

FirebaseのSNSでのサインアップ/サインインに使用するProviderを動的に変更したい。

whoiwhoi

総合スコア48

Firebase

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

TypeScript

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

React.js

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

1グッド

1クリップ

投稿2020/06/06 00:25

前提

FirebaseでSNSアカウントによるサインアップとサインイン機能を実装しています。
ReactとTypeScriptを使用しています。

tsx

1auth.signInWithPopup(new firebase.auth.GoogleAuthProvider())

上記のコードでGoogleアカウントによるサインアップとサインインは可能になります。

実現したいこと

サインアップとサインインに使えるSNSのアカウントごとにauth.signInWithPopup(...)を書かなければいけないため、押したSNSボタンに合わせて動的にProviderを切り替えたいです。

該当のソースコード

tsx

1const SNS = ["Google", "Twitter", "Facebook"] 2const SNSButton = SNS.map((item, index)=>( 3 <div key={index}> 4 <button onClick={signClick} name={item}>{item}</button> 5 </div> 6) 7 8const signClick =()=> { 9 if(sign === "Up") return signUp(); 10 // signはグローバルステートです。サインアップ、サインインを開くボタンを押す際に、setStateしています。 11 signIn(); 12} 13 14const signUp =()=> { 15 auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()) 16 ... 17} 18 19const signIn =()=> { 20 auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()) 21 ... 22} 23 24return( 25 <> 26 <h2>Sign {sign}</h2> 27 <div>{SNSButton}</div> 28 </> 29)

試したこと

ProviderをStateで管理して、signClick関数内でボタンのname属性を取得し、取得したname属性に沿ってswitchでProviderをsetStateしました。

tsx

1const googleProvider = new firebase.auth.GoogleAuthProvider(); 2const twitterProvider = new firebase.auth.TwitterAuthProvider(); 3const facebookProvider = new firebase.auth.FacebookAuthProvider(); 4const [provider, setProvider] = useState(googleProvider); 5 6const signClick = (e: any)=> { 7 const { name } = e.target; 8 switch (name) { 9 case "Google": 10 setProvider(googleProvider); 11 break; 12 case "Twitter": 13 setProvider(twitterProvider); 14 break; 15 case "Facebook": 16 setProvider(facebookProvider); 17 break; 18 default: 19 setProvider(googleProvider); 20 } 21 if(sign === "Up") return signUp(); 22 signIn(); 23} 24 25const signUp =()=> { 26 auth.signInWithPopup(provider) 27 ... 28} 29 30const signIn =()=> { 31 auth.signInWithPopup(provider) 32 ... 33}

上記コードは下記の問題点があります。

  • switchのsetProvider(twitterProvider)にのみIDE(VSCode)が下記のエラーを表示します

型 'TwitterAuthProvider' の引数を型 'SetStateAction<GoogleAuthProvider>' のパラメーターに割り当てることはできません。

  • signClick関数の引数eがany型

VSCodeがReact.MouseEvent<HTMLButtonElement, MouseEvent>を推論してくれますが、これを設定するとconst { name } = e.targetに下記のエラーが表示されます

プロパティ 'name' は型 'EventTarget' に存在しません。

  • そもそもsetProviderできていないです

switchのTwitterケースだけコメントアウトし、signUp関数頭でconsole.log(provider)を記述し、Facebookボタンを押したところ、Facebookアカウントのポップアップではなく、Googleアカウントのポップアップが表示されました。
「name属性が取得できておらず、初期値またはswitchのデフォルトが適用されているのかな」と思い、switchの直前にconsole.log(name)を記述し、Facebookボタンを押したところ、コンソールにはFacebookと表示されました。


実装方法にこだわりはないので、switchを使用することやProviderをstateで管理するなど、試したことに書いた方法論に執着は無いです。
実現したいことが実現でき、かつシンプルに書けることが理想なので、よりよい方法があれば解決策と合わせあてご教示いただきたいです。

DrqYuto👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

switchのsetProvider(twitterProvider)にのみIDE(VSCode)が下記のエラーを表示します

providerおよびsetProviderの型はuseStateの初期値として渡されたものから推論されます。

typescript

1// providerの型はGoogleAuthProviderに推論される 2const [provider, setProvider] = useState(googleProvider);

GoogleAuthProvider型のstateに対してTwitterAuthProvider型の変数をセットしようとしているのでエラーになっているわけです。useStateの呼び出しの際にジェネリクスに明示的に型を指定すれば解決するでしょう。providerはどれもAuthProviderというinterfaceを実装しているようなのでそれを指定します。

https://firebase.google.com/docs/reference/js/firebase.auth.AuthProvider

typescript

1// providerの型はAuthProviderに推論される 2const [provider, setProvider] = useState<AuthProvider>(googleProvider);

signClick関数の引数eがany型

targetではなくcurrentTargetを参照してください。イベントをバインドした要素(ここではbutton要素)そのものを指すのはcurrentTargetのほうです。nameはもちろん、他のプロパティも参照できるようになります。

そもそもsetProviderできていないです

useStateでproviderを保持するのをやめて、
signClickからsignUpやsignInのほうに引数でproviderを渡す形にするとどうでしょうか。

typescript

1const signClick = (e: React.MouseEvent<HTMLButtonElement>)=> { 2 const { name } = e.currentTarget; 3 let provider: AuthProvider; 4 switch (name) { 5 case "Google": 6 provider = googleProvider; 7 break; 8 case "Twitter": 9 provider = twitterProvider; 10 break; 11 case "Facebook": 12 provider = facebookProvider; 13 break; 14 default: 15 provider = googleProvider; 16 } 17 if(sign === "Up") return signUp(provider); 18 signIn(provider); 19} 20 21const signUp =(provider)=> { 22 auth.signInWithPopup(provider) 23 ... 24} 25 26const signIn =(provider)=> { 27 auth.signInWithPopup(provider) 28 ... 29}

投稿2020/06/06 04:19

markey

総合スコア355

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

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

whoiwhoi

2020/06/06 11:34

実装できました!&試したことの問題点の解決策をご教示くださりありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問