React项目中的ES6循环依赖

iwa*_*hka 6 javascript ecmascript-6 reactjs

我刚刚使用 React Native 设置了一个小测试项目。这对我来说都是新的(包括 ECMAScript 6)。Eslint 告诉我一些关于“循环依赖”的事情,我不知道如何解决这个问题。尽管如此,该代码仍然有效。

我的 package.json:

...
"dependencies": {
    "axios": "^0.19.0",
    "node-sass": "^4.12.0",
    "react": "16.8.3",
    "react-native": "0.59.9",
    "react-navigation": "^3.11.0"
},
"devDependencies": {
    "@babel/core": "7.4.5",
    "@babel/runtime": "7.4.5",
    "babel-eslint": "^10.0.1",
    "babel-jest": "24.8.0",
    "babel-plugin-module-resolver": "^3.2.0",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-import-resolver-babel-module": "^5.1.0",
    "eslint-plugin-import": "^2.17.3",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-react": "^7.13.0",
    "jest": "24.8.0",
    "metro-react-native-babel-preset": "0.54.1",
    "react-dom": "^16.8.6",
    "react-test-renderer": "16.8.3"
},
...
Run Code Online (Sandbox Code Playgroud)

src/index.jsx是主要的 JSX 文件:

import { Comp1 } from 'components';
...
Run Code Online (Sandbox Code Playgroud)

我创建了一个src/components/index.jsx来启用导入,例如

import { Comp1, Comp2, Comp3 } from 'components'
Run Code Online (Sandbox Code Playgroud)

代替

import { Comp1 } from 'components/comp1';
import { Comp2 } from 'components/comp2';
import { Comp3 } from 'components/comp3';
Run Code Online (Sandbox Code Playgroud)

该文件src/components/index.jsx如下所示:

export * from './button';
export * from './comp1';
...
Run Code Online (Sandbox Code Playgroud)

src/components/button/index.jsx:

import React from 'react';
import {
  Text,
  TouchableOpacity
} from 'react-native';
import style from './style';

const Button = ({ onPress, children }) => {
  const {
    buttonStyle,
    textStyle
  } = style;

  return (
    <TouchableOpacity onPress={onPress} style={buttonStyle}>
      <Text style={textStyle}>
        {children}
      </Text>
    </TouchableOpacity>
  );
};

export default Button;
export { Button };
Run Code Online (Sandbox Code Playgroud)

src/components/comp1/index.jsx:

import React from 'react';
import {
  Text,
  View
} from 'react-native';
import { Button } from 'components';
import style from './style';

const Comp1 = (props) => {
  const {
    textStyle,
    viewStyle
  } = style;

  return (
    <View style={viewStyle}>
      <Text style={textStyle}>some text</Text>
      <Button>Test</Button>
    </View>
  );
};

export default Comp1;
export { Comp1 };

Run Code Online (Sandbox Code Playgroud)

运行此设置会产生 eslint 错误import/no-cycle。代码本身可以工作。

如果我更改import { Button } from 'components'src/components/comp1/index.jsxno import { Button } from 'components/button'eslint 错误会弹出。

我想使用如上所述的简短导入语法,而不失去在彼此内部使用模块的可能性。有办法吗?

T.J*_*der 9

您的结构正在components/index.jsxcomp1/index.jsx(以及您拥有相同事物的其他结构)之间建立循环依赖关系。comp1/index.jsx从 导入components/index.jsx,从 导入comp1/index.jsx

\n

实际本机 ESM\xc2\xb9 模块和 CJS\xc2\xb2 或类似模块之间的循环运行时处理不同。两者都需要仔细处理循环,但它们的行为方式略有不同。如果您在捆绑程序或类似程序中将 ESM 转换为 CJS,这可能会特别令人困惑。

\n

当两个模块之间存在循环依赖性时(为了简单起见),这意味着在某些时候两个模块之一将在另一个模块之前运行,这意味着它从另一个模块获取的任何导入都将是未初始化的(ESM)或尚未定义(CJS)。因此,两个模块之一中的顶级代码还不能依赖于现有的导入。在 ESM 中,尝试使用未初始化的导出会引发错误;在 CJS 中,导出的值仅为undefined.

\n

在您的示例中,我不认为这是一个问题,因为循环中模块中的顶级代码不使用循环中其他模块的导入,它仅用于稍后调用的函数(comp1/index.jsx使用Button,但仅在Comp1调用时调用,并且不在顶层代码中调用。(过程可能比这更复杂,但是......)

\n

如果代码经过测试并且可以工作,您可以使用配置注释来禁用组件文件的该规则(如果它允许您这样做)。这可以让您在出现实际有问题的周期时保留全局规则,但不会为您已经测试过并知道良好的这些周期而烦恼。

\n
\n

\xc2\xb9 ESM = E CMA S cript模块,真正的原生 JavaScript 模块,如果仅使用importexport声明(而不是import()动态导入),则可以静态分析。

\n

\xc2\xb2 CJS = Common JSrequire ,使用对象的动态模块结构exports

\n