循环依赖在React Native中返回空对象

Luk*_*uke 17 react-native

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

在Alpha中要求Beta工作正常,但要求Alpha中的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);
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

ide*_*ide 26

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

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


随着importexport

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

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

var Alpha = React.createClass({
    /* ... */
});
export default Alpha;
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在运行时,export关键字创建一个中间对象(相当于module.exportsCommonJS中),并为其指定一个名为的属性default,其值为Alpha.因此,上述export陈述在概念上与此类似:

module.exports.default = Alpha;
Run Code Online (Sandbox Code Playgroud)

导入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
                }}
            />
        );
    },
});
Run Code Online (Sandbox Code Playgroud)

延迟访问是通过运行代码实现的,类似于:

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
                }}
            />
        );
    },
});
Run Code Online (Sandbox Code Playgroud)

require()

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

方法1:延迟加载

在用户从一个场景导航到下一个场景之前,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
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

虽然在这个特定的场景中没有必要为Beta.js做同样的事情,因为Alpha是第一个加载的组件,但这可能是一个好主意,所以你的组件都以相同的方式处理依赖循环.

方法2:单个模块

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

// AlphaBeta.js
var Alpha = React.createClass({...});
var Beta = React.createClass({...});
exports.Alpha = Alpha;
exports.Beta = Beta;
Run Code Online (Sandbox Code Playgroud)

要求它:

// index.js
var {Alpha, Beta} = require('./AlphaBeta');
Run Code Online (Sandbox Code Playgroud)