基于未声明的商店的React Navigation导致警告

时间:2019-03-17 16:37:16

标签: react-native react-navigation unstated

我在我的本机项目中使用react-navigation和Unstated。

我有一种情况要使用:

this.props.navigation.navigate("App")

成功登录后。

问题是我不希望直接通过分配给提交按钮的函数来完成它。我想基于一个全局的Unstated商店进行导航。

但是,这意味着我将需要使用Subscribe包装程序的条件INSIDE。这就是导致可怕的Warning: Cannot update during an existing state transition (such as within 'render').

的原因
  render() {
    const { username, password } = this.state;
    return (
      <Subscribe to={[MainStore]}>
        {({ auth: { state, testLogin } }) => {
          if (state.isAuthenticated) {
            this.props.navigation.navigate("App");
            return null;
          }
          console.log("rendering AuthScreen");
          return (
            <View style={styles.container}>
              <TextInput
                label="Username"
                onChangeText={this.setUsername}
                value={username}
                style={styles.input}
              />
              <TextInput
                label="Password"
                onChangeText={this.setPassword}
                value={password}
                style={styles.input}
              />
              {state.error && (
                <Text style={styles.error}>{state.error.message}</Text>
              )}
              <Button
                onPress={() => testLogin({ username, password })}
                color="#000"
                style={styles.button}
              >
                Sign in!
              </Button>
            </View>
          );
        }}
      </Subscribe>
    );

有效。但是正确的方法是什么? 我无权访问MainStore之外的Subscribe,因此也无法访问render之外。

2 个答案:

答案 0 :(得分:1)

我不确定反应导航模式,但是您可以在该组件周围使用包装器,该包装器订阅“ MainStore”,并将其作为道具传递给该组件。这样,您将可以在render方法之外访问“ MainStore”。

答案 1 :(得分:0)

此后,我找到了更好的解决方案。 我创建了一个现在可以在任何需要访问存储的组件(无论有无功能)上调用的HOC。这使我可以访问商店的状态和功能。这意味着,我可以随意使用原定的组件,钩子和所有组件。

是这样的:

WithUnstated.js

import React, { PureComponent } from "react";
import { Subscribe } from "unstated";

import MainStore from "../store/Main";

const withUnstated = (
  WrappedComponent,
  Stores = [MainStore],
  navigationOptions
) =>
  class extends PureComponent {
    static navigationOptions = navigationOptions;

    render() {
      return (
        <Subscribe to={Stores}>
          {(...stores) => {
            const allStores = stores.reduce(
              // { ...v } to force the WrappedComponent to rerender
              (acc, v) => ({ ...acc, [v.displayName]: { ...v } }),
              {}
            );
            return <WrappedComponent {...allStores} {...this.props} />;
          }}
        </Subscribe>
      );
    }
  };

export default withUnstated;

在此标头示例中的用法如下:

import React from "react";
import { Text, View } from "react-native";

import styles from "./styles";

import { states } from "../../services/data";
import withUnstated from "../../components/WithUnstated";
import MainStore from "../../store/Main";

const Header = ({
  MainStore: {
    state: { vehicle }
  }
}) => (
  <View style={styles.plateInfo}>
    <Text style={styles.plateTop}>{vehicle.plate}</Text>
    <Text style={styles.plateBottom}>{states[vehicle.state]}</Text>
  </View>
);

export default withUnstated(Header, [MainStore]);

因此,现在您不需要为渲染功能之外的所有可用商店创建所有百万包装组件。 作为额外的礼物,HOC接受了一系列商店,使其完全即插即用。并且-它与您的navigationOptions一起使用!

只需记住将displayName添加到您的商店(无论如何,ES-Lint都会提示您)。

这是一个简单的商店的样子:

import { Container } from "unstated";

class NotificationStore extends Container {
  state = {
    notifications: [],
    showNotifications: false
  };

  displayName = "NotificationStore";

  setState = payload => {
    console.log("notification store payload: ", payload);
    super.setState(payload);
  };

  setStateProps = payload => this.setState(payload);
}

export default NotificationStore;