javascript - 状态更改授权组件后, native 渲染 View 不会更新

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

大家好

我是这个 react-native 的新手,我正在尝试让 react-native、react router 4 和 firebase auth 工作。我想做的是检查用户是否已登录。如果他们已登录,它将显示“splash”组件,如果未登录,它将重定向到“/login”屏幕。

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

这是我要实现的流程:

  1. 用户可以在未授权时导航到“/login”和“/register”
  2. 如果未授权,用户无法导航到“/”
  3. 当用户被授权时,他们将转到“/”并且组件“splash”附加到该路径
  4. 组件“splash”具有受 HOC 保护的嵌套路由

我正在为我的项目使用 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>
    );
}
}

飞溅.js

import Home from "./../Home/Home";

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

登录.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>
);
};

我很感激我能得到的所有帮助和解释,谢谢你们先进

最佳答案

根据 firebase documentation , onAuthStateChanged添加一个监听器/观察器并返回一个非空函数():观察器的取消订阅函数。

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

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

  1. 再次在 PrivateRoute 组件上重新初始化监听器,该组件不执行任何操作。
  2. 取消订阅监听器,这可能会反过来增加额外开销,每当整个应用的身份验证状态发生变化

最佳方法是按如下方式进行:

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} />

关于javascript - 状态更改授权组件后, native 渲染 View 不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49608682/

相关文章:

javascript - 子项作为文本不会显示在 React Native 的文本组件中

ios - 适用于 iOS 的 Swift NativeModule 始终为 null

javascript - 如何使用 jquery Validation 验证 Formspree?

javascript - getElementsByClassName 选择具有给定类的所有元素

javascript - 如何在gulp中实现多源中流

javascript - 从javascript中的数组中删除重复的数组值

reactjs - React-Table 让一个单元格成为一个链接

javascript - 如何在同一存储库上使用 React.js 和 Node.js

ios - 是否可以在 React Native 中使用 iOS 13 系统字体?

react-native - 为什么 React Native 0.30 无法从 iPhone 设备上的开发服务器获取更改?