React Navigation на основе неустановленного магазина вызывает предупреждение - PullRequest
3 голосов
/ 17 марта 2019

Я использую реагирующую навигацию и Unstated в своем собственном проекте реагирования.

У меня есть ситуация, в которой я хотел бы использовать:

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

после успешного входа в систему.

Проблема в том, что я не хочу, чтобы это делалось напрямую из функции, назначенной кнопке отправки.Я хочу ориентироваться на основе глобального неустановленного хранилища.

Однако это означает, что мне нужно будет использовать условную INSIDE оболочки Subscribe.Это то, что приводит к страшным 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 ]

1 голос
/ 18 марта 2019

Я не уверен насчет шаблонов реагирования-навигации, но вы можете использовать обертку вокруг этого компонента, которая подписывается на 'MainStore', и передавать его этому компоненту в качестве реквизита.Таким образом, вы получите доступ к «MainStore» вне метода рендеринга.

0 голосов
/ 08 июля 2019

С тех пор я нашел лучшее решение.Я создал 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;
...