首页 > 解决方案 > 何时从 Authentication SwitchNavigator 导航?

问题描述

我正在我的 React Native 应用程序中设置身份验证流程,我几乎可以让一切正常工作,除了我无法确定使用this.props.navigation.navigate("Main");.

我的应用程序顶部有一个 Switch Navigator,它呈现身份验证堆栈(它自己的开关导航)和主堆栈:

// App.js

const AppContainer = createAppContainer(
  createSwitchNavigator({
    Auth: AuthNavigator,
    Main: MainTabNavigator,
  })
);

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <View style={styles.container}>
          <AppContainer />
        </View>
      </Provider>
    );
  }
}

登录屏幕现在是一个完整的虚拟设置(它调用本地 api 并且无论如何都会成功)。请注意render 方法开始处的条件:

// LoginView.js

class LoginView extends Component {
  state =  { username: "", password: "" };

  handleLogin() {
    this.props.login.call(this);
  }

  render() {
    if (this.props.user) {
      this.props.navigation.navigate("Main");
      return null;
    }

    return (
      <View style={styles.container}>
        <Overlay>
          <View style={styles.modalContainer}>
            <DotIndicator color={"darkgrey"} />
            <Text>Logging in...</Text>
          </View>
        </Overlay>

        // ... input components ...
        <Button
          title="Login"
          onPress={this.handleLogin.bind(this)}
        />
      </View>
    );
  }
}

export default connect(
  state => ({
    isLoading: state.auth.isLoading,
    user: state.auth.user,
    error: state.auth.error
  }),
  { login }
)(LoginView);

现在,这在技术上有效,但我得到了错误Warning: Cannot update during an existing state transition (such as withinrender ). Render methods should be a pure function of props and state.

我知道这是被抛出的,因为我正在navigate调用render. 说得通。

我尝试从我的登录操作导航:

export function login() {
  return dispatch => {
    dispatch({ type: "LOGIN_START" });
    fetch(url) // this will need to be a POST session (not a GET user)
      .then(res => res.json())
      .then(users => {
        dispatch({ type: "LOGIN_SUCCESS", payload: users[0] });
        console.log("Login succeeded");
        this.props.navigation.navigate("Main");
      })
      .catch(error => {
        console.warn("login failed");
        dispatch({ type: "LOGIN_FAILURE", payload: error });
      });
  };
}

它可以工作,但在关注点分离方面当然是非常错误的,当我尝试使用它来处理登录失败时,这种解决方案也并没有真正延伸。

我也考虑过在我的handleLogin()函数(由我的登录按钮调用)中执行它,有和没有 async/await:

  async handleLogin() {
    await this.props.login.call(this);
    console.log("Navigating to main screen");
    this.props.navigation.navigate("Main");
  }

但是导航发生在操作完成并且用户登录之前,一旦认证流程是真实的,这当然是不可接受的。(另外,当我使用 async/await 执行此操作时,“登录成功”会被记录两次!击败我)。确实感觉我在我的handleLogin()职能中走在正确的轨道上。

我在哪里navigate打电话?

标签: react-nativeredux

解决方案


我似乎找到了一些可行的方法,但它与 Redux 相去甚远,这让我有点不舒服。

我已经从 Redux 操作中提取了所有内容,并将其放入我的LoginView. 我在 Redux 术语中认为这没问题,因为程序需要了解授权过程和状态的唯一地方是授权流程本身(目前就其LoginView本身而言)。商店和应用程序的其余部分唯一需要知道的是用户的信息。

所以我login用一个简单的动作替换了我的 ReduxassignUser动作。在发布状态更改以激活我的“登录...”覆盖后,我已经将获取重构为performLogin从旧调用的 fetching。handleLogin

// authActions.js

export function assignUser(user) {
  return dispatch => {
    console.log("user", user);
    dispatch({ type: "LOGIN_SUCCESS", payload: user });
  };
}

// from LoginView.js

  performLogin() {
    fetch("http://127.0.0.1:3000/users") // this will need to be a POST session (not a GET user)
      .then(res => res.json())
      .then(users => {
        console.log("Login succeeded");
        this.props.assignUser(users[0]);
        console.log("Navigating to main screen");
        this.props.navigation.navigate("Main");
      })
      .catch(error => {
        console.warn("login failed", error);
        this.setState({isLoading: false})
      });
  }

  handleLogin() {
    this.setState({ isLoading: true }, this.performLogin);
  }

组件的其余部分LoginView与我原来的帖子中的相同。

我仍然很想知道是否有人有任何方法可以完成此操作,从而将操作完全保留在 Redux 中。


推荐阅读