【问题标题】:Cyclic dependency returns empty object in React Native循环依赖在 React Native 中返回空对象
【发布时间】:2015-04-22 20:01:42
【问题描述】:

我有两个相互导航的 React Native 组件(Alpha 和 Beta);但是,这会产生循环依赖,而 React Native 似乎无法处理这些。

在 Alpha 中要求 Beta 可以正常工作,但在 Beta 中要求 Alpha 返回一个空对象。尝试推送带有无效组件的路由时会引发错误。

循环依赖可以在 React Native 中工作吗?如果没有,我该如何解决?

代码

index.ios.js

'use strict';

var React = require('react-native');

var Alpha = require('./Alpha');

var {
    AppRegistry,
    NavigatorIOS,
    StyleSheet,
    Text,
    View,
} = React;

var ExampleProject = React.createClass({
    render() {
        return (
            <NavigatorIOS
                style={styles.container}
                initialRoute={{
                    component: Alpha,
                    title: Alpha.title,
                    wrapperStyle: styles.wrapper
                }} />
        );
    },
});

var styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    },
    wrapper: {
        paddingTop: 64
    }
});

AppRegistry.registerComponent('ExampleProject', () => ExampleProject);

Alpha.js

'use strict';

var React = require('react-native');
var Beta = require('./Beta');

var {
    StyleSheet,
    TouchableHighlight,
    View,
    Text
} = React;

var Alpha = React.createClass({
    statics: {
        title: 'Alpha'
    },

    goToBeta() {
        this.props.navigator.push({
            component: Beta,
            title: Beta.title,
            wrapperStyle: styles.wrapper
        });
    },

    render() {
        return (
            <View>
                <TouchableHighlight style={styles.linkWrap}
                    onPress={this.goToBeta}>
                    <Text>Go to Beta</Text>
                </TouchableHighlight>
            </View>
        );
    }
});

var styles = StyleSheet.create({
    linkWrap: {
        flex: 1,
        alignItems: 'center',
        padding: 30
    },
    wrapper: {
        paddingTop: 64
    }
});

module.exports = Alpha;

Beta.js

'use strict';

var React = require('react-native');
var Alpha = require('./Alpha');

var {
    StyleSheet,
    TouchableHighlight,
    View,
    Text
} = React;

var Beta = React.createClass({
    statics: {
        title: 'Beta'
    },

    goToAlpha() {
        this.props.navigator.push({
            component: Alpha,
            title: Alpha.title,
            wrapperStyle: styles.wrapper
        });
    },

    render() {
        return (
            <View>
                <TouchableHighlight style={styles.linkWrap}
                    onPress={this.goToAlpha}>
                    <Text>Go to Alpha</Text>
                </TouchableHighlight>
            </View>
        );
    }
});

var styles = StyleSheet.create({
    linkWrap: {
        flex: 1,
        alignItems: 'center',
        padding: 30
    },
    wrapper: {
        paddingTop: 64
    }
});

module.exports = Beta;

【问题讨论】:

标签: react-native


【解决方案1】:

这是路由组件的常见问题。有几种方法可以解决这个问题。一般来说,您希望 Alpha 避免在 Alpha 定义其导出之前要求 Beta,反之亦然。

幸运的是,JavaScript 的 importexport 关键字通过使用充当间接级别的中间对象延迟导入值来解决此问题。一个具体的例子更容易理解。


使用importexport

使用export 关键字从各自的文件中导出Alpha 和Beta,并使用import 关键字导入它们:

// Alpha.js
import Beta from './Beta';

var Alpha = React.createClass({
    /* ... */
});
export default Alpha;

这是因为在运行时,export 关键字会创建一个中间对象(相当于 CommonJS 中的 module.exports)并为其分配一个名为 default 的属性,其值为 Alpha。因此,上面的export 语句在概念上类似于:

module.exports.default = Alpha;

导入 Alpha 的文件然后获得对中间对象的引用,而不是 Alpha 本身,直到直接使用 Alpha。所以这里的这段代码实际上是懒惰地访问了Alpha:

import Alpha from './Alpha';

var ExampleProject = React.createClass({
    render() {
        return (
            <NavigatorIOS
                style={styles.container}
                initialRoute={{
                    component: Alpha,
                    title: Alpha.title,
                    wrapperStyle: styles.wrapper
                }}
            />
        );
    },
});

惰性访问是通过运行概念上类似于此的代码来实现的:

var AlphaExports = require('./Alpha');

var ExampleProject = React.createClass({
    render() {
        return (
            <NavigatorIOS
                style={styles.container}
                initialRoute={{
                    component: AlphaExports.default,
                    title: AlphaExports.default.title,
                    wrapperStyle: styles.wrapper
                }}
            />
        );
    },
});

require()

使用 CommonJS 的 require,您还有其他一些选择:

方法一:延迟加载

在用户从一个场景导航到下一个场景之前,Alpha 和 Beta 不需要彼此。要使应用程序达到此状态,Alpha 必须定义其导出(即,module.exports = Alpha 必须已经运行,您的应用程序才能呈现 Alpha 组件)。因此,当用户导航到显示 Beta 的场景时,Beta 要求 Alpha 是安全的,因此此时要求 Beta 是安全的。

// Alpha.js
var Alpha = React.createClass({
    goToBeta() {
        // Lazily require Beta, waiting until Alpha has been initialized
        var Beta = require('./Beta');

        this.props.navigator.push({
            component: Beta,
            title: Beta.title,
            wrapperStyle: styles.wrapper
        });
    }
});

尽管在这种特定情况下不需要对 Beta.js 执行相同的操作,因为 Alpha 是第一个加载的组件,但最好让所有组件都以相同的方式处理依赖循环。

方法 2:单个模块

另一种解决方案是将Alpha和Beta放在同一个JS文件中,以消除模块之间的循环。然后,您将从新的巨型模块中导出这两个组件。

// AlphaBeta.js
var Alpha = React.createClass({...});
var Beta = React.createClass({...});
exports.Alpha = Alpha;
exports.Beta = Beta;

需要它:

// index.js
var {Alpha, Beta} = require('./AlphaBeta');

【讨论】:

  • 我遇到了这个问题,方法 1:延迟加载对我有用。但我很好奇为什么这是必要的。两个模块都通过module.exports = X 声明了一个导出。这还不够吗?谢谢
  • 很好的答案@ide。谢谢。 :)
  • 这让我摆脱了@ide。如果可以的话,我会给你一个事后的赏金。取而代之的是……单票。很好的解释!感谢您花时间编写它。
猜你喜欢
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-03
相关资源
最近更新 更多