简体   繁体   English

基于Unstated store的React Navigation导致警告

[英]Unstated store based React Navigation causing warning

I'm using react-navigation and Unstated in my react native project. 我在反应本机项目中使用react-navigation和Unstated。

I have a situation where I would like use: 我有一个我想使用的情况:

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

after successfully signing in. 成功登录后。

Problem is I don't want it done directly from a function assigned to a submit button. 问题是我不希望它直接从分配给提交按钮的函数完成。 I want to navigate based upon a global Unstated store. 我想基于全球Unstated商店进行导航。

However, it means that I would need to use a conditional INSIDE of the Subscribe wrapper. 但是,这意味着我需要使用Subscribe包装器的条件INSIDE。 That is what leads to the dreaded Warning: Cannot update during an existing state transition (such as within 'render'). 这就是导致可怕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>
    );

It works. 有用。 But what's the correct way to do it? 但是这样做的正确方法是什么? I don't have access to MainStore outside of Subscribe and therefore outside of render . 我没有获得MainStore之外的Subscribe ,因此外界的render

I'm not sure about the react-navigation patterns but you could use a wrapper around this component which subscribes to 'MainStore' and pass it down to this component as a prop. 我不确定反应导航模式,但你可以使用这个组件的包装器订阅'MainStore'并将其作为prop传递给这个组件。 That way you'll have access to 'MainStore' outside the render method. 这样你就可以访问render方法之外的'MainStore'了。

I have since found a better solution. 我已经找到了更好的解决方案。 I created an HOC that I call now on any Component, functional or not, that requires access to the store. 我创建了一个HOC,我现在调用任何组件,无论是否有功能,需要访问商店。 That give me access to the store's state and functions all in props. 这使我可以访问商店的状态和功能所有的道具。 This means, I am free to use the component as it was intended, hooks and all. 这意味着,我可以自由地使用组件,钩子和所有。

Here's what it looks like: 这是它的样子:

WithUnstated.js 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;

Used like so in this Header example: 在此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]);

So now you don't need to create a million wrapper components for all the times you need your store available outside of your render function. 因此,现在您无需在渲染功能之外的所有时间内创建百万个包装器组件。 As, as an added goodie, the HOC accepts an array of stores making it completely plug and play. 作为一个额外的好东西,HOC接受了一系列商店,使其完全即插即用。 AND - it works with your navigationOptions! AND - 它适用于您的navigationOptions!

Just remember to add displayName to your stores (ES-Lint prompts you to anyway). 只需记住将displayName添加到您的商店(无论如何,ES-Lint会提示您)。

This is what a simple store looks like: 这是一个简单的商店看起来像:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM