简体   繁体   English

React Native:可从每个应用程序屏幕访问的自定义组件

[英]React Native: custom component that is accessible from every app screen

What is the best 'React' way of creating a custom component that can be accessible from any screen? 什么是创建可从任何屏幕访问的自定义组件的最佳“反应”方式?

Think of a custom Alert component . 想想自定义警报component I need it in every screen of my app, so when an error occurs I can show it. 我需要在我的应用程序的每个屏幕中,所以当出现错误时我可以显示它。

Currently I am doing it this way: 目前我这样做:

// AlertModal.js // AlertModal.js

import ... from ...;

const AlertModal = (props) => {

  const {isSuccess, headerText, bodyText, onClosed, isOpen, onBtnPress} = props;

  return (

      <Modal
        ...
        isOpen={isOpen}
        onClosed={() => onClosed()}
      >

        <View ...>

            <Text>{headerText}</Text>

          <Text>{bodyText}</Text>

          <Button
            ...
            onPress={() => onBtnPress()}
           >
              ...
           </Button>

        </View>

      </Modal>

  )
};

export default AlertModal;

//Foo.js //Foo.js

import ...from ...;

const Foo = (props) => {

  const { alertIsSuccess, alertHeaderText, alertBodyText, alertIsOpen, alertOnClosed, alertOnBtnPress, onBtnPress, ...rest } = props;

  return (
    <View style={}>

     ...     

      <View style={}>
        ...
      </View>


        <Button
          onPress={() => onBtnPress()}
        />

      <AlertModal
        isSuccess={alertIsSuccess}
        headerText={alertHeaderText}
        bodyText={alertBodyText}
        isOpen={alertIsOpen}
        onClosed={alertOnClosed}
        onBtnPress={alertOnBtnPress}
      />

    </View>
  )

};

export default QrCodeReader;

//FooContainer.js //FooContainer.js

import ... from ...;

class FooContainer extends Component {
    constructor(props) {
        super(props);

        this.state = {
          bar: false,
          baz: true,
          bac: '',
          bax: false,
          bav: '',

          // Alert
          alertIsOpen: false,
          alertIsSuccess: false,
          alertHeaderText: '',
          alertBodyText: '',
          alertOnClosed() {},
          alertOnBtnPress() {},
        };

      this.onBtnPress = this.onBtnPress.bind(this);
    }

    alert(isSuccess, headerText, bodyText, onBtnPress, onClosed) {

      const self = this;

      this.setState({
        alertIsOpen: true,
        alertIsSuccess: isSuccess,
        alertHeaderText: headerText,
        alertBodyText: bodyText,
        alertOnBtnPress: onBtnPress || function () { self.alertClose() },
        alertOnClosed: onClosed || function () {},
      });

    }

    alertClose() {

      this.setState({
        alertIsOpen: false,
      });

    }

    onBtnPress() {

        this.alert(
          true,
          'header text',
          'body text',
        )

    }

    render() {
        return (
          <Foo
            onBtnPress={this.onBtnPress}
            {...this.state}
          />
        );
    }
}

export default FooContainer;

As you can see it is a pain (and I think an incorrect way). 你可以看到它是一种痛苦(我认为这是一种不正确的方式)。 Doing this way I would need to include AlertModal component in every component of my app where I need to display alerts = duplicate props and making new unnecessary <AlertModal /> components. 这样做我需要在我的应用程序的每个component中包含AlertModal组件,我需要在其中显示警告=重复道具并创建新的不必要的<AlertModal />组件。

What is the correct way? 什么是正确的方法?

ps I use react-native-router-flux as a router in my app. ps我在我的应用程序中使用react-native-router-flux作为路由器。 pss I am coming to React-native from a Meteor.js + Cordova . pss我来自Meteor.js + Cordova React-native There I can just create one modal and include it in the main layout and show/hide it when necessary with the appropriate dynamic text inside it. 在那里,我可以创建一个模态并将其包含在主layout并在必要时显示/隐藏它,并在其中包含相应的动态文本。

This is how I navigate in my app: 这就是我在我的应用中导航的方式:

//Main.js
class Main extends Component {
      render() {
        return (
          <Router backAndroidHandler={() => true}>
            <Scene key="root">
              <Scene key="login" type='reset' component={SignInContainer} initial={true} hideNavBar={true}/>
              <Scene key="qrCode" type='reset' component={FooContainer} hideNavBar={true} />
            </Scene>
          </Router>
        );
      }
}

Based on the fact that you use react-native-router-flux I can suggest: 基于您使用react-native-router-flux的事实,我可以建议:

Rework AlertModal into scene component on is own, do not use Modal. 将AlertModal返回到场景组件中是自己的,不要使用Modal。 You can control what to display in it by passing properties. 您可以通过传递属性来控制要在其中显示的内容。 Include AlertModal component in your router as 'modal' schema like this: 将路由器中的AlertModal组件包含为“模态”架构,如下所示:

import AlertModal from '../components/AlertModal';
//Main.js
class Main extends Component {
  render() {
    return (
      <Router backAndroidHandler={() => true}>
        <Scene key="root">
          <Scene key="login" type='reset' component={SignInContainer} initial={true} hideNavBar={true}/>
          <Scene key="qrCode" type='reset' component={FooContainer} hideNavBar={true} />
          <Scene key="alertModal" duration={250} component={AlertModal} schema="modal" direction="vertical" hideNavBar={true} />
        </Scene>
      </Router>
    );
  }
}

And then you can just call it from any scene with: 然后你可以从任何场景调用它:

Actions.alertModal({ >optional props you want to pass< });

Not sure if is desired behaviour but this kind of modals may be dismissed in Android with back button. 不确定是否有所需的行为,但这种模式可能会在Android中用后退按钮解除。 If not, there is a way around it. 如果没有,那就有办法解决它。

This might not be the best solution, but what you can do is use the context functionality of React. 这可能不是最好的解决方案,但您可以使用React的上下文功能。 Essentially, pass a function reference that triggers your component to show/hide (maybe by changing its state , for instance) into the context. 本质上,传递一个函数引用,触发您的组件显示/隐藏(例如,通过将其state更改为)到上下文中。 Then every child in the hierarchy should be able to call that function. 然后,层次结构中的每个子节点都应该能够调用该函数。

However, Facebook discourages using the context functionality, and it might give you some problems when debugging, since it is not as easy to track as your props/state. 但是,Facebook不鼓励使用上下文功能,并且在调试时可能会给您一些问题,因为它不像您的道具/状态那样容易跟踪。

Another solution that comes to mind might be playing with Redux, creating an action that changes a property to which the component is subscribed. 想到的另一个解决方案可能是使用Redux,创建一个操作来更改组件订阅的属性。 Then all your other components can just dispatch that action, changing the value of the property that makes the modal component to display. 然后,所有其他组件都可以dispatch该操作,更改使模式组件显示的属性的值。

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

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