使用mapDispatchToProps避免无阴影的错误


76

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

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


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

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

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

我知道我可以添加注释以禁止显示警告,但是对每个组件执行此操作似乎都是多余且乏味的。


您可以重命名setFilterFilterButton({ setFilter })FilterButton({ setFilter }))。之所以有意义(某种程度上)是因为inFilterButton的props中setFilterdispatch函数实际上是绑定了该函数的原始函数。
吉拉德·阿特齐

重命名前后相同。
Kerumen

我的意思是仅在function FilterButton({ setFilter }) {和中重命名<button onClick={setFilter}>Click</button>。您可以使用修改后的代码更新问题吗?
吉拉德·阿特齐

我不能重命名它,function FilterButton({ setFilter })因为它必须与setFilter实际的道具名称匹配。
Kerumen

3
您不能在将其传递给导出行上的函数时重新分配它吗?因此,export default connect(null, {filter: setFilter})(FilterButton);然后在此之上function FilterButton ({filter}) {(或您喜欢的任何新变量名称)。这样,您就不会在上限范围内隐藏变量,并且在查看代码时很清楚。
尼克·巴特利特

Answers:


189

这里有四个选项:

1.禁用规则。

为什么?

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

为什么不?

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

换句话说,如果您没有使用分解并从道具中获取动作,则setFilter()不会分派动作(因为您将直接调用导入的动作,而不是通过props通过props调用关联的动作props.setFilter(),后者会react-redux自动为您分派)。

通过清除变量阴影,您和/或您的IDE更有可能发现错误。

怎么样?

向文件中添加eslintConfig属性package.json执行此操作的一种方法

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

2.将变量传递到时,重新分配变量connect()

为什么?

您将从无阴影规则的安全性中受益,并且,如果您选择遵守命名约定,则这非常明确。

为什么不?

介绍样板。

如果不使用命名约定,则现在必须为每个操作提供备用名称(仍然有意义)。而且,相同的动作在各个组件中的命名方式可能会有所不同,这使得更难于熟悉动作本身。

如果您确实使用命名约定,则名称会变得很长且重复。

怎么样?

没有命名约定:

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是重复的(如果要破坏所有其他非动作道具,则前后矛盾)。

怎么样?

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规则

怎么样?

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

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

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

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

如果您要传递多个模块,请使用带有REST语法的对象分解

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简洁语法的偏爱,因此不妨抛出带有隐式返回的arrow函数:

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

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

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

1
谢谢!这肯定是公认的答案。
Yan Takushevich

5
很好的书面答案。虽然,在Disable the rule:)之后,您应该停止阅读:)
Mrchief

3
究竟如何no-shadow帮助防止调用原始操作?当您正确使用它(假定已变形的道具)时,它将引发错误,而在调用原始操作时则不会发生错误。@GollyJer的答案是一个很好的补充,应该添加到该答案的第一部分。考虑到所有因素,这很有可能是最佳做法。
低音

1
按照惯例,我很想只$添加操作的名称并使用mapDispatchToProps的简写形式,但是$即使使用jQuery ,我也总是会感到有些不舒服。
凯文·迪斯

2
将变量传递到connect()时,我正在使用#2重新分配变量。我要添加一个动作后缀(即setFilter是setFilterAction)。感谢您提供其他选择以及对每个选择的见解。
肯特

11

第五种选择:

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

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

为什么?

您不需要可变阴影,但在某些情况下无法解决它。

为什么不?

确实不希望代码库中有变量阴影。😝


我喜欢这个选项,但对我不起作用,我仍然看到错误
saas_joel

6

选项六。

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规则的方法可用于多行代码。如果您传递更多参数并将它们划分为多行代码,则可能会很有用。

为什么?

对于某些用例,这是一个简单而合适的选择(例如,您的团队/组织使用特定的es-lint设置,不鼓励/禁止修改这些设置)。它禁用了代码行中的es-lint错误,但不影响mapDispatchToProps语法,并且该规则在代码行外仍然完全有效。

为什么不?

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


2

我进行了4.调整,实现了我想称呼的选项8。

8.以不同的名称导入方法

为什么?

它具有与导入整个模块相同的好处,但不会与其他规则冲突,例如,不要使用通配符import(airbnb)

为什么不?

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

怎么样?

对于单方法情况

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

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

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

1

选项7 ...

7.使用容器组件

为什么?

这是一种已知的模式,您将获得额外的好处,即可以将组件与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);

另一个要点:“为什么不”:现在可以导入名称与未连接到redux的组件非常相似的组件。
tao_oat

1

通过在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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.