🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Firebase

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

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

Q&A

解決済

1回答

1569閲覧

Reactにてfirebaseの関数内でsetStateが使えない

3aki

総合スコア14

Firebase

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

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

0グッド

0クリップ

投稿2021/02/10 17:06

編集2021/02/11 23:09

前提・実現したいこと

Reactの環境にてfirebase-toolsのonAuthStateChanged関数でuserデータを受け取って保持したいのですが、どういじってもsetStateが使えません。

発生している問題・エラーメッセージ

n.setState is not function

該当のソースコード

JavaScript

1import Firebase, { Firestore } from './Firebase'; 2 3export default class Auth { 4 constructor(props) { 5 this.state = { 6 user: null, 7 }; 8 } 9 10 initialization = () => { 11 Firebase.auth().onAuthStateChanged(function(user) { 12 if (user) { 13 console.log(user); 14 this.setState({ user: user }); // エラー箇所 15 console.log(this.state.user); 16 } else { 17 console.log("user is null"); 18 } 19 }); 20 } 21}

試したこと

this.setStateの行を別の関数にうつして、その関数を呼び出し。

JavaScript

1import Firebase, { Firestore } from './Firebase'; 2 3export default class Auth { 4 constructor(props) { 5 this.state = { 6 user: null, 7 }; 8 } 9 10 initialization = () => { 11 Firebase.auth().onAuthStateChanged(function(user) { 12 if (user) { 13 console.log(user); 14 this.setUserState(user); 15 console.log(this.state.user); 16 } else { 17 console.log("user is null"); 18 } 19 }); 20 } 21 22 setUserState = user => { 23 this.setState({ user: user }); // エラー箇所 24 } 25}

function (user)を別の関数にうつして、その関数を呼び出し。

JavaScript

1import Firebase, { Firestore } from './Firebase'; 2 3export default class Auth { 4 constructor(props) { 5 this.state = { 6 user: null, 7 }; 8 } 9 10 initialization = () => { 11 Firebase.auth().onAuthStateChanged(onAuthStateChanged); 12 } 13 14 onAuthStateChanged = user => { 15 if (user) { 16 console.log(user); 17 this.setUserState(user); 18 console.log(this.state.user); 19 } else { 20 console.log("user is null"); 21 } 22 } 23 24 setUserState = user => { 25 this.setState({ user: user }); // エラー箇所 26 } 27}

それぞれの関数をconstructorでbind(this)。

JavaScript

1export default class Auth { 2 constructor(props) { 3 this.state = { 4 user: null, 5 }; 6 7 this.initialization = this.initialization.bind(this); 8 this.onAuthStateChanged = this.onAuthStateChanged.bind(this); 9 this.setUserState = this.setUserState.bind(this); 10 } 11 12 initialization = () => { 13 Firebase.auth().onAuthStateChanged(onAuthStateChanged); 14 } 15 16 onAuthStateChanged = user => { 17 if (user) { 18 console.log(user); 19 this.setUserState(user); 20 console.log(this.state.user); 21 } else { 22 console.log("user is null"); 23 } 24 } 25 26 setUserState = user => { 27 this.setState({ user: user }); // エラー箇所 28 } 29}

useStateに置き換え。
エラー→https://reactjs.org/docs/error-decoder.html/?invariant=321

JavaScript

1import { useState } from "react"; 2import Firebase, { Firestore } from './Firebase'; 3 4export default class Auth { 5 constructor(props) { 6 this.initialization = this.initialization.bind(this); 7 } 8 9 initialization = () => { 10 Firebase.auth().onAuthStateChanged(user => { 11 const [user_, setUser] = useState(null); // エラー箇所 12 if (user) { 13 console.log(user); 14 setUser(user); 15 console.log(user_); 16 } else { 17 console.log("user is null"); 18 } 19 }); 20 } 21}

Promiseを使用

JavaScript

1import Firebase, { Firestore } from './Firebase'; 2 3export default class Auth { 4 constructor(props) { 5 this.state = { 6 user: null, 7 }; 8 9 this.initialization = this.initialization.bind(this); 10 } 11 12 initialization = () => { 13 return new Promise((resolve, reject) => { 14 Firebase.auth().onAuthStateChanged(user => { 15 if (user) { 16 resolve(user); 17 } else { 18 reject(null); 19 } 20 }); 21 }).then(user => { 22 console.log(user); 23 this.setState({ user: user }); // エラー箇所 24 console.log(this.state.user); 25 }).catch(() => console.log("user is null")); 26 } 27}

補足情報(FW/ツールのバージョンなど)

"@testing-library/jest-dom": "^5.11.6", "@testing-library/react": "^11.2.2", "@testing-library/user-event": "^12.6.0", "date-fns": "^2.16.1", "esri-leaflet-geocoder": "^2.3.4", "firebase": "^8.2.1", "firebase-tools": "^9.2.0", "formik": "^2.2.6", "leaflet": "^1.7.1", "react": "^17.0.1", "react-datepicker": "^3.3.0", "react-dom": "^17.0.1", "react-leaflet": "^3.0.5", "react-router-dom": "^5.2.0", "react-scripts": "4.0.0", "styled-components": "^5.2.1", "typescript": "^4.1.3", "web-vitals": "^0.2.4"

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

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

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

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

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

hoshi-takanori

2021/02/10 17:29

クラスコンポーネントの場合、this が何を指しているかをご確認ください。
3aki

2021/02/11 09:05

クラスを指しています。
hoshi-takanori

2021/02/11 18:56

function キーワードを使った無名関数の場合、this が指すものは無名関数の呼ばれ方によりますが、たぶん期待するオブジェクトにはなってないと思います。bind(this) するか、アロー関数にする必要があるのでは。
3aki

2021/02/11 22:56

試したことに有る通り、試しています。
guest

回答1

0

ベストアンサー

とりあえずこれで動きました。

  • Auth を React のクラスコンポーネントにしないと setState は使えないので、React.Component を継承しました。
  • initialization というメソッドは勝手には呼ばれないと思うので、constructor で呼びましょう。(Auth を unmount する可能性があるなら、componentDidMount で initialization を呼んで、componentWillUnmount で unsubscribe した方がいいかも。)
  • this.setState の this をバインドするには、initialization そのものと、onAuthStateChanged に渡す無名関数の両方を bind(this) するか、アロー関数にする必要があります。

js

1import React from 'react'; 2import Firebase from 'firebase/app'; 3import 'firebase/auth'; 4 5export default class Auth extends React.Component { 6 constructor(props) { 7 super(props); 8 this.state = { 9 user: null, 10 }; 11 this.initialization(); 12 } 13 14 initialization = () => { 15 Firebase.auth().onAuthStateChanged((user) => { 16 if (user) { 17 console.log(user); 18 this.setState({ user: user }); 19 console.log(this.state.user); 20 } else { 21 console.log("user is null"); 22 } 23 }); 24 } 25 26 render() { 27 const user = this.state.user; 28 return ( 29 <p>Auth: {user ? user.uid : 'none'}</p> 30 ); 31 } 32}

投稿2021/02/12 01:25

hoshi-takanori

総合スコア7899

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

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

3aki

2021/02/12 09:33

setStateってJavaScriptの機能じゃないんですね、知りませんでした。 initializationは訳合ってAuth呼び出し元でauth.initialization()しています。 thisをバインドするのに「bind(this) する」のはわかるのですが、「アロー関数にする」のでも問題ないということでしょうか?それはアロー関数にするとバインドの効果も得られるということでしょうか? (あと、bind(this)もアロー関数も気持ち悪いので他の方法はあったりしますでしょうか?)
hoshi-takanori

2021/02/12 09:46

Auth をご自分で呼び出してるとしたら、それは React コンポーネントではないってことでは? そうだとすると回答の前提が成り立ちませんね…。 「bind(this)もアロー関数も気持ち悪い」と言われても、JavaScript はそういう言語なので…。 なお、bind(this) とアロー関数ではメカニズムが全然違って、アロー関数は this を特別扱いしないので、アロー関数が作られた時 (つまりオブジェクト生成時) の this がそのまま使われるってことになります。 https://qiita.com/suin/items/a44825d253d023e31e4d
maisumakun

2021/02/12 09:55

> あと、bind(this)もアロー関数も気持ち悪いので他の方法はあったりしますでしょうか? それで納得がいくかどうかはともかく、「thisを別の名前の変数に入れておいて、コールバックではそちらを参照する」ような方法も考えられます。
3aki

2021/02/12 10:09

> Auth をご自分で呼び出してるとしたら、それは React コンポーネントではないってことでは? そうだとすると回答の前提が成り立ちませんね…。 これの「Auth をご自分で呼び出してるとしたら、それは React コンポーネントではない」の意味がわからないです。React.Componentを継承しても呼び出したらReact.Componentが無視されるということでしょうか? url先、この後で読んでみます。 thisを別の名前の変数に入れるというのもなかなかに違和感を感じるので、まだラムダ式に馴染みのあるアロー関数を使うことにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問