使用 mapDispatchToProps 避免 no-shadow eslint 错误

Avoid no-shadow eslint error with mapDispatchToProps

我有以下组件在 FilterButton props 上触发 no-shadow ESlint 错误。

import { setFilter } from '../actions/filter';


function FilterButton({ setFilter }) {
  return (
    <button onClick={setFilter}>Click</button>
  );
}

export default connect(null, { setFilter })(FilterButton);

如何在保持 mapDispatchToProps 的简洁语法和 ESlint 规则的同时避免警告?

我知道我可以添加评论来抑制警告,但对每个组件都这样做似乎是多余且乏味的。

这里有四个选项:

1。禁用规则。

为什么?

这是避免 ESLint 错误的最简单方法。

为什么不呢?

no-shadow 规则有助于防止在使用 react-redux 时出现一个非常常见的错误。也就是说,尝试调用原始的、未连接的操作(不会自动调度)。

换句话说,如果你没有使用解构并从 props 中获取动作,setFilter() 将不会调度动作(因为你会调用直接导入操作,而不是通过 props.setFilter() 通过 props 调用连接的操作,react-redux 会自动为您调度)。

通过清理 variable shadowing,您 and/or 您的 IDE 更有可能发现错误。

怎么办?

eslintConfig 属性 添加到您的 package.json 文件是 one way to do this

"eslintConfig": {
    "rules": {
      "no-shadow": "off",
    }
  }

2。将变量传递给 connect().

时重新分配变量

为什么?

您受益于 no-shadow 规则的安全性,而且,如果您选择遵守命名约定,那是非常明确的。

为什么不呢?

它介绍了样板文件。

如果您不使用命名约定,您现在必须为每个操作想出备用名称(仍然有意义)。并且相同的操作可能会在组件之间以不同的方式命名,这使得熟悉操作本身变得更加困难。

如果您使用命名约定,名称会变得又长又重复​​。

怎么办?

没有命名约定:

import { setFilter } from '../actions/filter';

function FilterButton({ filter }) {
  return (
    <button onClick={filter}>Click</button>
  );
}

export default connect(null, { filter: setFilter })(FilterButton);

命名约定:

import { setFilter, clearFilter } from '../actions/filter';

function FilterButton({ setFilterConnect, clearFilterConnect }) {
  return (
    <button onClick={setFilterConnect} onBlur={clearFilterConnect}>Click</button>
  );
}

export default connect(null, {
  setFilterConnect: setFilter,
  clearFilterConnect: clearFilter,
})(FilterButton);

3。不要破坏道具的动作。

为什么?

通过显式使用 props 对象的方法,您一开始就不需要担心阴影。

为什么不呢?

props/this.props 为您的所有动作添加前缀是重复的(如果您正在解构所有其他 non-action 道具,则不一致)。

怎么办?

import { setFilter } from '../actions/filter';

function FilterButton(props) {
  return (
    <button onClick={props.setFilter}>Click</button>
  );
}

export default connect(null, { setFilter })(FilterButton);

4。导入整个模块。

为什么?

简洁。

为什么不呢?

其他开发人员(或您未来的自己)可能无法理解正在发生的事情。根据您遵循的风格指南,您可能会破坏 no-wildcard-imports rule.

怎么办?

如果您只是从一个模块传递动作创建者:

import * as actions from '../actions/filter';

function FilterButton({ setFilter }) {
  return (
    <button onClick={setFilter}>Click</button>
  );
}

export default connect(null, actions)(FilterButton);

如果您要传入多个模块,请使用 object destructuring with rest syntax:

import * as filterActions from '../actions/filter';
import * as otherActions from '../actions/other';

// all exported actions from the two imported files are now available as props
function FilterButton({ setFilter, clearFilter, setOther, clearOther }) {
  return (
    <button onClick={setFilter}>Click</button>
  );
}

export default connect(null, { ...filterActions, ...otherActions })(FilterButton);

并且由于您在评论中提到了对 ES6 简洁语法的偏好,不妨使用隐式 return:

抛出箭头函数
import * as actions from '../actions/filter';

const FilterButton = ({ setFilter }) => <button onClick={setFilter}>Click</button>;

export default connect(null, actions)(FilterButton);

第五个选项:

5。通过 eslintrc 规则允许特定例外。

module.exports = {
  rules: {
    'no-shadow': [
      'error',
      {
        allow: ['setFilter'],
      },
    ],
  }
}

为什么?

您不想要变量阴影,但在某些情况下无法绕过它。

为什么不呢?

真的不想在您的代码库中使用变量阴影。

选项六。

6。禁用特定代码行的 es-lint 规则

import { setFilter } from '../actions/filter';


// eslint-disable-next-line no-shadow
function FilterButton({ setFilter }) {
  return (
    <button onClick={setFilter}>Click</button>
  );
}

export default connect(null, { setFilter })(FilterButton);

import { setFilter } from '../actions/filter';


/* eslint-disable no-shadow */
function FilterButton({ setFilter }) {
/* es-lint-enable */
  return (
    <button onClick={setFilter}>Click</button>
  );
}

export default connect(null, { setFilter })(FilterButton);

与第一种不同的是,第二种暂时禁用es-lint规则的方法可以用于多行代码。如果您传递更多参数并将它们分成多行代码,它会很有用。

为什么?

对于某些用例来说,这是一个简单且合适的选项(例如,您的 team/organization 使用特定的 es-lint 设置,并且 discouraged/forbidden 可以修改这些设置)。 它禁用代码行中的 es-lint 错误,但不影响 mapDispatchToProps 语法,并且该规则在代码行之外仍然完全有效。

为什么不呢?

您不希望或被禁止使用此类注释来膨胀您的代码。 您不想或被禁止影响 es-lint 行为。

选项 7...

7。使用容器组件

为什么?

这是一个 known pattern 并且您可以获得将组件与 redux 存储分离的额外好处,使它们更容易重用。

为什么不呢?

现在每个组件需要两个文件。

怎么样?

// FilterButton.jsx

export default function FilterButton({ setFilter }) {
  return (
    <button onClick={setFilter}>Click</button>
  );
}
// FilterButtonRedux.jsx

import FilterButton from './FilterButton';
import { setFilter } from '../actions/filter';

export default connect(null, { setFilter })(FilterButton);

我调整了 4. 并实现了我想称之为选项 8 的内容。

8。以不同名称导入方法

为什么?

它具有与导入整个模块相同的好处,但不会与其他规则冲突,例如Do not use wildcard imports(airbnb).

为什么不呢?

它添加了一个不必要的变量声明,可能会引起混淆。

怎么办?

对于单一方法案例

import { setFilter as setFilterConnect } from '../actions/filter';

function FilterButton({ setFilter }) {
  return <button onClick={setFilter}>Click</button>;
}

export default connect(
  null,
  { setFilter: setFilterConnect }
)(FilterButton);

随着 v7.1.0 中添加的新 Hooks API,您可以完全摆脱变量和 mapDispatchToProps

import { useDispatch } from 'react-redux'
import { setFilter } from '../actions/filter';

function FilterButton() {
  const dispatch = useDispatch()
  return (
    <button onClick={dispatch(setFilter())}>Click</button>
  );
}

export default FilterButton;