3

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

我有一种情况,我想使用:

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

成功登录后。

问题是我不希望它直接从分配给提交按钮的功能中完成。我想基于全球未说明的商店进行导航。

但是,这意味着我需要使用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.

4

2 回答 2

1

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

于 2019-03-18T13:22:08.330 回答
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;

在这个 Header 示例中像这样使用:

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 接受一系列商店,使其完全即插即用。并且 - 它适用于您的导航选项!

只需记住将 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;
于 2019-07-07T23:58:02.780 回答