如何在Firebase + React app

时间:2018-02-09 01:13:02

标签: reactjs typescript firebase mobx mobx-react

我正在开发一个Mobx React应用程序,当我登录/login页面时,该应用程序一直给我这些错误。

首先,我的代码:

index.tsx

import 'semantic-ui-css/semantic.min.css';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';
import { initializeApp } from 'firebase';
import { useStrict } from 'mobx';
import { Provider } from 'mobx-react';
import { AppContainer } from 'react-hot-loader';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';

import App from './components/App';
import UserStore from './stores/UserStore';

const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();

const stores = {
  UserStore: UserStore,
  RoutingStore: routingStore
};

const history = syncHistoryWithStore(browserHistory, routingStore);

const config = {
  apiKey: 'my api key',
  authDomain: 'example.firebaseapp.com'
}
initializeApp(config);

function startApp() {
  console.log('in startApp');
  ReactDOM.render(
    <Provider {...stores}>
      <Router history={history}>
        <AppContainer>
          <App />
        </AppContainer>
      </Router>
    </Provider>
    ,
    document.getElementById('root')
  );
}
startApp();

App.tsx

import * as React from 'react';
import { Switch, Route, withRouter, Link } from 'react-router-dom';
import { inject, observer } from 'mobx-react';
import { Menu } from 'semantic-ui-react';
import { UserStore, UserStoreProps } from '../stores/UserStore';
import { hot } from 'react-hot-loader';
import { auth, initializeApp } from 'firebase';

import { Header } from './Header';
import { Login } from './Login';

interface AppProps {
    UserStore?: UserStoreProps,
    RoutingStore?: {
        location: any,
        push: any,
        goBack: any
    }
}

@inject('UserStore', 'RoutingStore')
@observer
class App extends React.Component<AppProps, {}> {
    componentDidMount() {
        if (!this.props.UserStore.isLoaded){
            console.log('in App componentDidMount');
            this.props.UserStore.pullUser();
        }
    }

    render() {
        const { location, push, goBack } = this.props.RoutingStore;
        console.log(!!this.props.UserStore.currentUser);
        if (this.props.UserStore.isLoaded) {
            return (
                <div>
                    <Header />
                    <Switch>
                        <Route path="/login" component={Login} />
                    </Switch>
                </div>
            );
        }
        return (
            <div>Loading</div>
        );

    }
}

declare const module: any;

export default hot(module)(App);

Login.tsx

import * as React from 'react';
import { Switch, Route, withRouter, Link } from 'react-router-dom';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { Menu, Button } from 'semantic-ui-react';
import { Grid, Header, Segment, Icon, Divider, Form } from 'semantic-ui-react';
import { UserStore, UserStoreProps } from '../stores/UserStore';
import { hot } from 'react-hot-loader';
import { auth } from 'firebase';

interface AppProps {
    UserStore?: UserStoreProps 
}

@inject('UserStore')
@observer
export class Login extends React.Component<AppProps, {}> {
    render() {
        return (
            <Grid centered={true}>
                <Grid.Column style={{ maxWidth: 450 }}>
                    <Segment>
                        {this.props.UserStore.currentUser.email}
                    </Segment>
                </Grid.Column>
            </Grid>
        );
    }
}

UserStore.tsx

import { observable, action } from 'mobx';
import { auth, UserInfo } from 'firebase';
import { useStrict } from 'mobx';

useStrict(true);

export interface UserStoreProps {
    currentUser: UserInfo,
    pullUser: Function,
    isLoaded: boolean
}

export class UserStore<UserStoreProps> {
    @observable currentUser: UserInfo;
    @observable isLoaded = false;

    @action pullUser() {
        const fetchUser = () => new Promise((resolve, reject) => {
            auth().onAuthStateChanged((user: UserInfo) => {
                if (user) {
                    resolve(user);
                } else {
                    reject(console.log)
                }
            });
        });
        return fetchUser().then(action((user: UserInfo) => {
            console.log('in fetchUser callback');
            this.currentUser = user;
            this.isLoaded = true;
        }))
        .catch(action(error => {
            this.isLoaded = true;
        }))
    }
}

export default new UserStore();

现在,这是我在Chrome DevTools控制台中进行硬刷新时看到的内容:

控制台日志

[HMR] Waiting for update signal from WDS...
app.js:6793 in startApp
app.js:6560 false
app.js:6551 in App componentDidMount
login:1 Slow network is detected. Fallback font will be used while loading: https://fonts.gstatic.com/s/lato/v14/1YwB1sO8YE1Lyjf12WNiUA.woff2
vendor.js:99216 [WDS] Hot Module Replacement enabled.
app.js:6868 in fetchUser callback
app.js:6560 true
app.js:6560 true
vendor.js:48021 Uncaught TypeError: Cannot read property '0' of null
    at bindDependencies (vendor.js:48021)
    at trackDerivedFunction (vendor.js:48003)
    at Reaction.webpackJsonp../node_modules/mobx/lib/mobx.module.js.Reaction.track (vendor.js:48207)
    at ProxyComponent.reactiveRender [as render] (app.js:2257)
    at finishClassComponent (vendor.js:58485)
    at updateClassComponent (vendor.js:58462)
    at beginWork (vendor.js:58837)
    at performUnitOfWork (vendor.js:60836)
    at workLoop (vendor.js:60900)
    at HTMLUnknownElement.callCallback (vendor.js:51154)
bindDependencies @ vendor.js:48021
trackDerivedFunction @ vendor.js:48003
webpackJsonp../node_modules/mobx/lib/mobx.module.js.Reaction.track @ vendor.js:48207
reactiveRender @ app.js:2257
finishClassComponent @ vendor.js:58485
updateClassComponent @ vendor.js:58462
beginWork @ vendor.js:58837
performUnitOfWork @ vendor.js:60836
workLoop @ vendor.js:60900
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
renderRoot @ vendor.js:60978
performWorkOnRoot @ vendor.js:61626
performWork @ vendor.js:61579
batchedUpdates @ vendor.js:61698
batchedUpdates @ vendor.js:52942
reactionScheduler @ vendor.js:48325
runReactions @ vendor.js:48301
endBatch @ vendor.js:47772
endAction @ vendor.js:45897
executeAction @ vendor.js:45864
res @ vendor.js:45852
Promise resolved (async)
UserStore.pullUser @ app.js:6867
executeAction @ vendor.js:45861
res @ vendor.js:45852
App.componentDidMount @ app.js:6552
f @ app.js:2121
commitLifeCycles @ vendor.js:59382
commitAllLifeCycles @ vendor.js:60558
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
commitRoot @ vendor.js:60662
performWorkOnRoot @ vendor.js:61629
performWork @ vendor.js:61579
requestWork @ vendor.js:61490
scheduleWorkImpl @ vendor.js:61344
scheduleWork @ vendor.js:61301
scheduleTopLevelUpdate @ vendor.js:61805
updateContainer @ vendor.js:61843
(anonymous) @ vendor.js:65838
unbatchedUpdates @ vendor.js:61714
renderSubtreeIntoContainer @ vendor.js:65837
render @ vendor.js:65902
startApp @ app.js:6794
(anonymous) @ app.js:6796
./src/index.tsx @ app.js:6819
__webpack_require__ @ manifest.js:713
fn @ manifest.js:118
0 @ app.js:6908
__webpack_require__ @ manifest.js:713
webpackJsonpCallback @ manifest.js:26
(anonymous) @ app.js:1
vendor.js:60359 The above error occurred in the <App> component:
    in App (created by inject-App-with-UserStore-RoutingStore)
    in inject-App-with-UserStore-RoutingStore (created by HotExportedinject-App-with-UserStore-RoutingStore)
    in AppContainer (created by HotExportedinject-App-with-UserStore-RoutingStore)
    in HotExportedinject-App-with-UserStore-RoutingStore
    in AppContainer
    in Router
    in Provider

React will try to recreate this component tree from scratch using the error boundary you provided, AppContainer.
logCapturedError @ vendor.js:60359
captureError @ vendor.js:61152
renderRoot @ vendor.js:61003
performWorkOnRoot @ vendor.js:61626
performWork @ vendor.js:61579
batchedUpdates @ vendor.js:61698
batchedUpdates @ vendor.js:52942
reactionScheduler @ vendor.js:48325
runReactions @ vendor.js:48301
endBatch @ vendor.js:47772
endAction @ vendor.js:45897
executeAction @ vendor.js:45864
res @ vendor.js:45852
Promise resolved (async)
UserStore.pullUser @ app.js:6867
executeAction @ vendor.js:45861
res @ vendor.js:45852
App.componentDidMount @ app.js:6552
f @ app.js:2121
commitLifeCycles @ vendor.js:59382
commitAllLifeCycles @ vendor.js:60558
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
commitRoot @ vendor.js:60662
performWorkOnRoot @ vendor.js:61629
performWork @ vendor.js:61579
requestWork @ vendor.js:61490
scheduleWorkImpl @ vendor.js:61344
scheduleWork @ vendor.js:61301
scheduleTopLevelUpdate @ vendor.js:61805
updateContainer @ vendor.js:61843
(anonymous) @ vendor.js:65838
unbatchedUpdates @ vendor.js:61714
renderSubtreeIntoContainer @ vendor.js:65837
render @ vendor.js:65902
startApp @ app.js:6794
(anonymous) @ app.js:6796
./src/index.tsx @ app.js:6819
__webpack_require__ @ manifest.js:713
fn @ manifest.js:118
0 @ app.js:6908
__webpack_require__ @ manifest.js:713
webpackJsonpCallback @ manifest.js:26
(anonymous) @ app.js:1
vendor.js:48068 Uncaught TypeError: Cannot read property 'length' of null
    at clearObserving (vendor.js:48068)
    at Reaction.webpackJsonp../node_modules/mobx/lib/mobx.module.js.Reaction.dispose (vendor.js:48249)
    at ProxyComponent.componentWillUnmount (app.js:2282)
    at callComponentWillUnmountWithTimer (vendor.js:59344)
    at HTMLUnknownElement.callCallback (vendor.js:51154)
    at Object.invokeGuardedCallbackDev (vendor.js:51193)
    at invokeGuardedCallback (vendor.js:51050)
    at safelyCallComponentWillUnmount (vendor.js:59351)
    at commitUnmount (vendor.js:59477)
    at unmountHostComponents (vendor.js:59816)
clearObserving @ vendor.js:48068
webpackJsonp../node_modules/mobx/lib/mobx.module.js.Reaction.dispose @ vendor.js:48249
componentWillUnmount @ app.js:2282
callComponentWillUnmountWithTimer @ vendor.js:59344
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
safelyCallComponentWillUnmount @ vendor.js:59351
commitUnmount @ vendor.js:59477
unmountHostComponents @ vendor.js:59816
commitDeletion @ vendor.js:59846
commitAllHostEffects @ vendor.js:60538
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
commitRoot @ vendor.js:60627
performWorkOnRoot @ vendor.js:61629
performWork @ vendor.js:61579
batchedUpdates @ vendor.js:61698
batchedUpdates @ vendor.js:52942
reactionScheduler @ vendor.js:48325
runReactions @ vendor.js:48301
endBatch @ vendor.js:47772
endAction @ vendor.js:45897
executeAction @ vendor.js:45864
res @ vendor.js:45852
Promise resolved (async)
UserStore.pullUser @ app.js:6867
executeAction @ vendor.js:45861
res @ vendor.js:45852
App.componentDidMount @ app.js:6552
f @ app.js:2121
commitLifeCycles @ vendor.js:59382
commitAllLifeCycles @ vendor.js:60558
callCallback @ vendor.js:51154
invokeGuardedCallbackDev @ vendor.js:51193
invokeGuardedCallback @ vendor.js:51050
commitRoot @ vendor.js:60662
performWorkOnRoot @ vendor.js:61629
performWork @ vendor.js:61579
requestWork @ vendor.js:61490
scheduleWorkImpl @ vendor.js:61344
scheduleWork @ vendor.js:61301
scheduleTopLevelUpdate @ vendor.js:61805
updateContainer @ vendor.js:61843
(anonymous) @ vendor.js:65838
unbatchedUpdates @ vendor.js:61714
renderSubtreeIntoContainer @ vendor.js:65837
render @ vendor.js:65902
startApp @ app.js:6794
(anonymous) @ app.js:6796
./src/index.tsx @ app.js:6819
__webpack_require__ @ manifest.js:713
fn @ manifest.js:118
0 @ app.js:6908
__webpack_require__ @ manifest.js:713
webpackJsonpCallback @ manifest.js:26
(anonymous) @ app.js:1
app.js:3600 TypeError: Cannot read property '0' of null
    at bindDependencies (vendor.js:48021)
    at trackDerivedFunction (vendor.js:48003)
    at Reaction.webpackJsonp../node_modules/mobx/lib/mobx.module.js.Reaction.track (vendor.js:48207)
    at ProxyComponent.reactiveRender [as render] (app.js:2257)
    at finishClassComponent (vendor.js:58485)
    at updateClassComponent (vendor.js:58462)
    at beginWork (vendor.js:58837)
    at performUnitOfWork (vendor.js:60836)
    at workLoop (vendor.js:60900)
    at HTMLUnknownElement.callCallback (vendor.js:51154)

请注意,上面的UserStore.pullUser @ app.js:6867就是这一行:

const fetchUser = () => new Promise((resolve, reject) => {

所以,我认为这个问题与我如何使用我从firebase action()观察者创建的Promise调用auth().onAuthStateChanged()有关。除此之外,我不确定会出现什么问题。

Login组件仍显示currentUser.email,但我正试图摆脱上面的控制台错误。

1 个答案:

答案 0 :(得分:0)

显然,此问题是由react-hot-loader引起的。

v4.0.0-beta.21更新到v4.0.0-beta.22修复了它。