admin管理员组

文章数量:1134247

I have the following component that triggers a no-shadow ESlint error on the FilterButton props.

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


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

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

How can I avoid the warning while keeping both the concise syntax of mapDispatchToProps and the ESlint rule?

I know I can add a comment to suppress the warning but doing it for every components seems redundant and tedious.

I have the following component that triggers a no-shadow ESlint error on the FilterButton props.

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


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

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

How can I avoid the warning while keeping both the concise syntax of mapDispatchToProps and the ESlint rule?

I know I can add a comment to suppress the warning but doing it for every components seems redundant and tedious.

Share Improve this question edited Jun 8, 2016 at 8:59 Kerumen asked Jun 7, 2016 at 14:53 KerumenKerumen 4,3412 gold badges20 silver badges34 bronze badges 8
  • You can rename setFilter (FilterButton({ setFilter }) to FilterButton({ setFilter })). It makes sense (sort of) because the functions that's in FilterButton's props is actually the original setFilter with the dispatch function bound to it. – Gilad Artzi Commented Jun 7, 2016 at 17:59
  • Before and after rename are the same. – Kerumen Commented Jun 8, 2016 at 9:01
  • I meant renaming only in function FilterButton({ setFilter }) { and <button onClick={setFilter}>Click</button>. Can you update your question with the edited code? – Gilad Artzi Commented Jun 8, 2016 at 9:21
  • I can't rename it in function FilterButton({ setFilter }) because it has to match the name of the prop which is setFilter actually. – Kerumen Commented Jun 8, 2016 at 9:58
  • 3 Can't you just reassign when passing it in to the function on the export line? So, export default connect(null, {filter: setFilter})(FilterButton); and then above that just function FilterButton ({filter}) { (or whatever new variable name you prefer). This way you're not shadowing the variable in the upper scope, and that's clear when looking at the code. – Nick Bartlett Commented Jun 12, 2016 at 18:55
 |  Show 3 more comments

6 Answers 6

Reset to default 207

There are four options here:

1. Disable the rule.

Why?

It's the easiest way to avoid the ESLint error.

Why Not?

The no-shadow rule helps to prevent a very common bug when using react-redux. That is, attempting to invoke the raw, unconnected action (which does not automatically get dispatched).

In other words, if you were not using destructuring and grabbing the action from props, setFilter() would not dispatch the action (because you'd be invoking the imported action directly, as opposed to invoking the connected action through props via props.setFilter(), which react-redux automatically dispatches for you).

By cleaning up variable shadowing, you and/or your IDE are more likely to pick up on the error.

How?

Adding a eslintConfig property to your package.json file is one way to do this.

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

2. Reassign the variable when passing it into connect().

Why?

You benefit from the safety of the no-shadow rule, and, if you choose to adhere to a naming convention, it's very explicit.

Why Not?

It introduces boilerplate.

If you do not use a naming convention, you now have to come up with alternate names (that still make sense) for every action. And chances are that the same actions will be named differently across components, making it harder to become familiar with the actions themselves.

If you do use a naming convention, names become long and repetitive.

How?

Without naming convention:

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

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

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

With naming convention:

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. Don't destructure actions off of props.

Why?

By explicitly using the method off of the props object, you don't need to worry about shadowing to begin with.

Why Not?

Prepending all of your actions with props/this.props is repetitive (and inconsistent if you're destructuring all of your other non-action props).

How?

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

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

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

4. Import the entire module.

Why?

It's concise.

Why Not?

Other developers (or your future self) may have trouble understanding what's going on. And depending on the style guide you're following, you might be breaking the no-wildcard-imports rule.

How?

If you're simply passing in action creators from one module:

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

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

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

If you're passing in multiple modules, use 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);

And since you mentioned a preference for ES6's concise syntax in the comments, might as well throw in the arrow function with an implicit return:

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

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

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

A fifth option:

5. Allow a specific exception via eslintrc rules.

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

Why?

You don't want variable shadowing but can't get around it in certain cases.

Why Not?

You really don't want variable shadowing in your code base.

本文标签: javascriptAvoid noshadow eslint error with mapDispatchToPropsStack Overflow