在状态更改auth组件后,本机渲染视图不会更新

时间:2018-04-02 09:28:29

标签: javascript reactjs react-native react-router firebase-authentication

嗨,大家好

我是这个本地反应的新手,我正在努力让反应原生,反应路由器4和firebase auth工作。我要做的是检查用户是否已登录。如果他们已登录,则会显示“splash”组件,如果未登录,则会重定向到“/ login”界面。

我确实关注了react router 4 auth文档,但我无法让它工作。现在我想知道我在这里缺少什么,如果有人可以向我解释这一点,那么我理解为什么它不起作用。

这是我想要实现的流程:

  1. 用户可以在未授权时导航至'/ login'和'/ register'
  2. 如果用户未被初始化,则用户无法导航到“/”
  3. 当用户被初始化时,他们将转到'/'并且组件'splash'附加到该路径
  4. 组件'splash'具有受HOC保护的嵌套路由
  5. 我正在为我的项目使用create-react-native-app,这是我的文件。

    app.js(根组件)

    export default class App extends React.Component {
    constructor() {
        super();
        this.state = {
            isAuth: false,
            email: "",
            password: ""
        };
    }
    
    onHandleLogin = (e, type) => {
        const event = e.nativeEvent.text;
        this.setState({ [type]: event });
    };
    
    onSubmitLogin = () => {
        const email = this.state.email;
        const password = this.state.password;
        firebase
            .auth()
            .signInWithEmailAndPassword(email, password)
    
            .catch(err => {
                console.log("error:", err);
            });
    };
    
    isLoggedIn = () => {
        firebase.auth().onAuthStateChanged(user => {
            if (user) {
                this.setState({ isAuth: true });
                return true;
            } else {
                this.setState({ isAuth: false });
                return false;
            }
        });
    };
    
    componentDidMount() {
        this.isLoggedIn();
    }
    
    render() {
        const PrivateRoute = ({ component: Component, ...rest }) => (
            <Route
                {...rest}
                render={props =>
                    this.isLoggedIn() ? (
                        <Component {...props} />
                    ) : (
                        <Redirect
                            to={{
                                pathname: "/login",
                                state: { from: props.location }
                            }}
                        />
                    )
                }
            />
        );
        return (
            <NativeRouter>
                <View style={styles.container}>
                    <Switch>
                        <Route
                            path="/login"
                            render={props => (
                                <Login
                                    {...props}
                                    submitFunc={this.onSubmitLogin}
                                    login={this.onHandleLogin}
                                    msg={this.state.isAuth}
                                />
                            )}
                        />
                        <Route path="/register" component={Register} />
                        <PrivateRoute path="/" component={Splash} />
                    </Switch>
                </View>
            </NativeRouter>
        );
    }
    }
    

    Splash.js

    import Home from "./../Home/Home";
    
    const Splash = () => {
        return (
            <View style={styles.container}>
                <Route exact path="/" component={Home} />
            </View>
        );
    };
    

    Login.js

    const Login = ({ login, submitFunc }) => {
    return (
        <KeyboardAwareScrollView
            resetScrollToCoords={{ x: 0, y: 0 }}
            contentContainerStyle={styles.formContainer}
        >
            <InputContainer style={styles.inputContainer}>
                <Logo source={logo} />
                <Input
                    inputStyle={styles.input2}
                    onChange={e => login(e, "email")}
                    placeholder="Email"
                    clearButtonMode="always"
                    containerStyle={styles.input}
                    leftIcon={
                        <Icon
                            containerStyle={styles.iconContainer}
                            name="at"
                            size={20}
                            type="font-awesome"
                            color="#b2b2b2"
                        />
                    }
                />
                <Input
                    inputStyle={styles.input2}
                    onChange={e => login(e, "password")}
                    placeholder="Password"
                    clearButtonMode="always"
                    containerStyle={styles.input}
                    secureTextEntry={true}
                    leftIcon={
                        <Icon
                            containerStyle={styles.iconContainer}
                            name="lock"
                            size={20}
                            type="font-awesome"
                            color="#b2b2b2"
                        />
                    }
                />
                <Button
                    title="Log in"
                    buttonStyle={styles.button}
                    titleStyle={styles.buttonTitle}
                    onPress={() => submitFunc()}
                />
                <Button
                    title="Forgot your password?"
                    buttonStyle={styles.buttonLink}
                    titleStyle={styles.buttonLinkTitle}
                />
                <ForgotContainer>
                    <Text style={styles.text}>Don't have an account? </Text>
                    <Link component={TouchableOpacity} to="/register">
                        <Text>Create one</Text>
                    </Link>
                </ForgotContainer>
            </InputContainer>
        </KeyboardAwareScrollView>
    );
    };
    

    我感谢所有帮助和解释,谢谢高级人员

3 个答案:

答案 0 :(得分:1)

根据firebase documentationonAuthStateChanged添加一个侦听器/观察者并返回一个非null函数():观察者的取消订阅函数。

  

onAuthStateChanged(nextOrObserver, error, completed) returns function()

查看代码,有两件事你做错了

  1. 再次在PrivateRoute组件重新初始化侦听器,该组件不执行任何操作。
  2. 只要身份验证状态针对您的整个应用发生更改
  3. ,听众就可以unsubscribing反过来添加额外的开销

    最佳方法是按照以下步骤进行

    componentDidMount() {
        // Bind the variable to the instance of the class.
        this.authFirebaseListener = firebase.auth().onAuthStateChanged((user) => {
          this.setState({
            loading: false,  // For the loader maybe
            user, // User Details
            isAuth: true
          });
        });
    
      }
    
    componentWillUnmount() {
       this.authFirebaseListener && this.authFirebaseListener() // Unlisten it by calling it as a function
    }
    

    并在PrivateRoute组件中,使用this.state

    将其注入您的组件(如果您希望组件分开,或者直接注入它)
    const PrivateRoute = ({ component: Component, isAuth, ...rest }) => ( // Pass it as a prop where your component is injected
            <Route
                {...rest}
                render={props =>
                    isAuth ? (
                        <Component {...props} />
                    ) : (
                        <Redirect
                            to={{
                                pathname: "/login",
                                state: { from: props.location }
                            }}
                        />
                    )
                }
            />
        );
    

    <PrivateRoute path="/" isAuth={this.state.isAuth} component={Splash} />
    

答案 1 :(得分:0)

确定这是否有问题但是this.isLoggedIn没有调用函数

this.isLoggedIn()实际上正在调用一个函数

答案 2 :(得分:0)

您应该在App渲染功能中检查this.state.isAuth而不是this.isLoggedIn()

this.isLoggedIn没有返回任何内容,并且总是伪造的(未定义),因此您将始终转到重定向案例。