Cyclic dependency returns empty object in React Native

后端 未结 1 1673
执念已碎
执念已碎 2020-12-13 07:38

I have two React Native Components (Alpha and Beta) that navigate to one another; however, this produces a cyclic dependency and React Native doesn’t seem to handle those.

相关标签:
1条回答
  • 2020-12-13 07:57

    This is a common problem with routing components. There are a couple of ways to approach this. In general, you want Alpha to avoid requiring Beta before Alpha has defined its exports and vice versa.

    Fortunately, JavaScript's import and export keywords address this issue by lazily importing values using an intermediate object that acts as a level of indirection. A specific example is a lot easier to understand.


    With import and export

    Use the export keyword to export Alpha and Beta from their respective files, and use the import keyword to import them:

    // Alpha.js
    import Beta from './Beta';
    
    var Alpha = React.createClass({
        /* ... */
    });
    export default Alpha;
    

    This works because at runtime, the export keyword creates an intermediate object (equivalent to module.exports in CommonJS) and assigns a property named default to it with the value of Alpha. So, the above export statement is conceptually similar to this:

    module.exports.default = Alpha;
    

    The files that import Alpha then get a reference to the intermediate object, not Alpha itself until Alpha is directly used. So this code here actually lazily accesses Alpha:

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

    The lazy access is implemented by running code conceptually similar to this:

    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
                    }}
                />
            );
        },
    });
    

    With require()

    Using CommonJS's require, you have some other options:

    Approach 1: Lazy Loading

    Alpha and Beta don't need each other until the user navigates from one scene to the next. For the app to reach this state, Alpha must have defined its exports (that is, module.exports = Alpha must have run for your app to have rendered an Alpha component). So, when the user is navigating to the scene displaying Beta, it is safe for Beta to require Alpha and therefore it is safe to require Beta at this point in time.

    // 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
            });
        }
    });
    

    Although it isn't necessary to do the same for Beta.js in this specific scenario because Alpha is the first component loaded, it's probably a good idea so that your components all handle dependency cycles the same way.

    Approach 2: Single Module

    Another solution is to put Alpha and Beta in the same JS file to remove a cycle between modules. You would then export both components from the new mega-module.

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

    To require it:

    // index.js
    var {Alpha, Beta} = require('./AlphaBeta');
    
    0 讨论(0)
提交回复
热议问题