Я пытался создать логин с помощью firebase, используя проект firebaseui-web-react
.
Я следовал этому примеру, сделанному firebaseui-web-react
людьми.Вы можете найти базовый файл здесь , но я вставлю его в этот вопрос:
/**
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// React core.
import React from 'react';
import ReactDOM from 'react-dom';
// Firebase.
import firebase from 'firebase/app';
import 'firebase/auth';
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
// Styles
import styles from './app.css'; // This uses CSS modules.
import './firebaseui-styling.global.css'; // Import globally.
// Get the Firebase config from the auto generated file.
const firebaseConfig = require('./firebase-config.json').result;
// Instantiate a Firebase app.
const firebaseApp = firebase.initializeApp(firebaseConfig);
/**
* The Splash Page containing the login UI.
*/
class App extends React.Component {
uiConfig = {
signInFlow: 'popup',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID,
],
callbacks: {
signInSuccessWithAuthResult: () => false,
},
};
state = {
isSignedIn: undefined,
};
/**
* @inheritDoc
*/
componentDidMount() {
this.unregisterAuthObserver = firebaseApp.auth().onAuthStateChanged((user) => {
this.setState({isSignedIn: !!user});
});
}
/**
* @inheritDoc
*/
componentWillUnmount() {
this.unregisterAuthObserver();
}
/**
* @inheritDoc
*/
render() {
return (
<div className={styles.container}>
<div className={styles.logo}>
<i className={styles.logoIcon + ' material-icons'}>photo</i> My App
</div>
<div className={styles.caption}>This is a cool demo app</div>
{this.state.isSignedIn !== undefined && !this.state.isSignedIn &&
<div>
<StyledFirebaseAuth className={styles.firebaseUi} uiConfig={this.uiConfig}
firebaseAuth={firebaseApp.auth()}/>
</div>
}
{this.state.isSignedIn &&
<div className={styles.signedIn}>
Hello {firebaseApp.auth().currentUser.displayName}. You are now signed In!
<a className={styles.button} onClick={() => firebaseApp.auth().signOut()}>Sign-out</a>
</div>
}
</div>
);
}
}
// Load the app in the browser.
ReactDOM.render(<App/>, document.getElementById('app'));
Я реализовал его, используя Typescript, и он работал.Затем я решил провести рефакторинг, потому что хотел сохранить все, что касается моего провайдера входа в систему, в другом классе, чтобы я мог переключиться на поддельную реализацию для целей тестирования.
Поэтому я реализовал это следующим образом:
LoginProvider.ts
export default interface LoginProvider {
unregister(): void
register(f:(user:any)=>void): void
actualProvider(): any
actualConfig(): any
}
FirebaseLoginProvider.ts
import LoginProvider from './LoginProvider';
export default class FirebaseLoginProvider implements LoginProvider {
private firebaseApp: any
private uiConfig: any
private unregisterAuthObserver: () => void
constructor(firebaseApp: any, uiConfig: any) {
this.uiConfig = uiConfig
this.firebaseApp = firebaseApp
}
public register(f:(user:any)=>void): void {
this.unregisterAuthObserver = this.firebaseApp.auth().onAuthStateChanged((user: any) => {
console.log("state changed " + !!user)
f(user)
}).bind(this)
}
public unregister(): void {
this.unregisterAuthObserver()
}
public actualProvider(): any {
return this.firebaseApp.auth()
}
public actualConfig(): any {
return this.uiConfig
}
}
Login.tsx
import 'firebase/auth';
import './firebase-global.css';
import * as React from 'react';
import { RouteComponentProps, withRouter } from "react-router-dom";
import LoginProvider from './LoginProvider';
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
interface Props {
};
interface State {
isSignedIn: boolean
}
interface HomeProps extends RouteComponentProps<Props> {
loginProvider: LoginProvider
}
class Login extends React.Component<HomeProps, State> {
state = {
isSignedIn: false
}
constructor(props: HomeProps) {
super(props);
}
componentDidMount() {
this.props.loginProvider.register((user) => {
this.setState({ isSignedIn: !!user } as State);
})
}
componentWillUnmount() {
this.props.loginProvider.unregister();
}
render() {
const signedIn = this.state.isSignedIn
return (
<div className='container'>
{!signedIn &&
<div>
<StyledFirebaseAuth
className='firebaseUi'
uiConfig={this.props.loginProvider.actualConfig()}
firebaseAuth={this.props.loginProvider.actualProvider()} />
</div>
}
{signedIn && this.props.history.goBack()}
</div>
);
}
}
export default withRouter(Login);
Моя реализация работает правильно, но я получаю это предупреждение в консоли браузера и не могу понять, почему.
Warning: Cannot update during an existing state transition (such as within 'render'). Render methods should be a pure function of props and state.
У меня также есть следующая трассировка стека:
React 8
listener createTransitionManager.js:46
notifyListeners createTransitionManager.js:65
notifyListeners createTransitionManager.js:64
setState createBrowserHistory.js:78
handlePop createBrowserHistory.js:103
confirmTransitionTo createTransitionManager.js:36
handlePop createBrowserHistory.js:101
handlePopState createBrowserHistory.js:85
go createBrowserHistory.js:214
goBack createBrowserHistory.js:218
render Login.tsx:55
React 13
componentDidMount Login.tsx:34
unregisterAuthObserver FirebaseLoginProvider.ts:16
next index.cjs.js:1303
sendOne index.cjs.js:1407
Дело в том, что я не видел проблемы с другой реализацией, но я просто извлекаю вещи в методы и классы, поэтому я не понимаю, почему она дает мне эту ошибку там, где ее раньше не было.
Кажется, проблема связана с react-router
, где я пытаюсь сделать:
{signedIn && this.props.history.goBack()}
Но если я сделаю этот вызов внутри componentDidMount
, он не будет вызван после страницы входа в firebaseзакрывается.
Я, вероятно, скучаюкое-что о жизненном цикле React.Не могли бы вы помочь мне решить проблему?