Vermeiden Sie mit mapDispatchToProps einen Eslint-Fehler ohne Schatten

74

Ich habe die folgende Komponente, die einen no-shadowESlint-Fehler auf dem auslöst FilterButton props.

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


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

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

Wie kann ich die Warnung vermeiden, während sowohl mapDispatchToPropsdie präzise Syntax als auch die ESlint-Regel beibehalten werden?

Ich weiß, dass ich einen Kommentar hinzufügen kann, um die Warnung zu unterdrücken, aber es scheint überflüssig und mühsam, dies für alle Komponenten zu tun.

Kerumen
quelle
Sie können setFilter( FilterButton({ setFilter })in FilterButton({ setFilter })) umbenennen . Es ist sinnvoll, weil die Funktionen in FilterButtonden Requisiten tatsächlich das Original sind, setFilteran das die dispatchFunktion gebunden ist.
Gilad Artzi
Vor und nach dem Umbenennen sind gleich.
Kerumen
Ich meinte nur in function FilterButton({ setFilter }) {und umzubenennen <button onClick={setFilter}>Click</button>. Können Sie Ihre Frage mit dem bearbeiteten Code aktualisieren?
Gilad Artzi
Ich kann es nicht umbenennen, function FilterButton({ setFilter })da es mit dem Namen der Requisite übereinstimmen muss, die setFiltertatsächlich ist.
Kerumen
3
Können Sie es nicht einfach neu zuweisen, wenn Sie es an die Funktion in der Exportzeile übergeben? Also, export default connect(null, {filter: setFilter})(FilterButton);und dann einfach darüber function FilterButton ({filter}) {(oder welchen neuen Variablennamen Sie bevorzugen). Auf diese Weise schattieren Sie die Variable nicht im oberen Bereich, und das ist klar, wenn Sie sich den Code ansehen.
Nick Bartlett

Antworten:

184

Hier gibt es vier Möglichkeiten:

1. Deaktivieren Sie die Regel.

Warum?

Dies ist der einfachste Weg, um den ESLint-Fehler zu vermeiden.

Warum nicht?

Die No-Shadow-Regel hilft, einen sehr häufigen Fehler bei der Verwendung zu vermeiden react-redux. Das heißt, der Versuch, die rohe, nicht verbundene Aktion aufzurufen (die nicht automatisch ausgelöst wird).

Mit anderen Worten, wenn Sie keine Destrukturierung verwenden und die Aktion von Requisiten abrufen setFilter()würden , würde die Aktion nicht ausgelöst (da Sie die importierte Aktion direkt aufrufen würden, anstatt die verbundene Aktion über Requisiten über aufzurufen props.setFilter(), die react-reduxautomatisch für Sie versendet ).

Wenn Sie die variable Schattierung bereinigen , werden Sie und / oder Ihre IDE den Fehler mit größerer Wahrscheinlichkeit erkennen.

Wie?

Das Hinzufügen einer eslintConfigEigenschaft zu Ihrer package.jsonDatei ist eine Möglichkeit, dies zu tun .

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

2. Weisen Sie die Variable beim Übergeben neu zu connect().

Warum?

Sie profitieren von der Sicherheit der No-Shadow-Regel. Wenn Sie sich für die Einhaltung einer Namenskonvention entscheiden, ist diese sehr explizit.

Warum nicht?

Es führt Boilerplate ein.

Wenn Sie keine Namenskonvention verwenden, müssen Sie jetzt für jede Aktion alternative Namen (die immer noch sinnvoll sind) erstellen. Und es besteht die Möglichkeit, dass dieselben Aktionen in verschiedenen Komponenten unterschiedlich benannt werden, was es schwieriger macht, sich mit den Aktionen selbst vertraut zu machen.

Wenn Sie eine Namenskonvention verwenden, werden Namen lang und wiederholen sich.

Wie?

Ohne Namenskonvention:

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

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

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

Mit Namenskonvention:

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. Zerstören Sie keine Aktionen von Requisiten.

Warum?

Wenn Sie die Methode off des Requisitenobjekts explizit verwenden, müssen Sie sich zunächst nicht um das Abschatten kümmern.

Warum nicht?

Das Vorbereiten aller Ihrer Aktionen mit props/ this.propswiederholt sich (und ist inkonsistent, wenn Sie alle anderen Requisiten ohne Aktion zerstören).

Wie?

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

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

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

4. Importieren Sie das gesamte Modul.

Warum?

Es ist prägnant.

Warum nicht?

Andere Entwickler (oder Ihr zukünftiges Selbst) haben möglicherweise Probleme zu verstehen, was los ist. Abhängig von dem Styleguide, dem Sie folgen, verstoßen Sie möglicherweise gegen die No-Wildcard-Import-Regel .

Wie?

Wenn Sie einfach Aktionsersteller aus einem Modul übergeben:

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

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

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

Wenn Sie mehrere Module übergeben, verwenden Sie die Objektdestrukturierung mit Restsyntax :

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

Und da Sie in den Kommentaren eine Präferenz für die prägnante Syntax von ES6 erwähnt haben, können Sie auch die Pfeilfunktion mit einer impliziten Rückgabe einfügen:

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

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

export default connect(null, actions)(FilterButton);
Jabacchetta
quelle
1
Vielen Dank! Dies sollte auf jeden Fall die akzeptierte Antwort sein.
Yan Takushevich
4
Sehr gut geschriebene Antwort. Obwohl man nachher aufhören sollte zu lesen Disable the rule:)
Mrchief
3
Wie genau kann no-shadowverhindert werden, dass die Raw-Aktion aufgerufen wird? Es wird ein Fehler ausgegeben, wenn Sie es richtig machen (vorausgesetzt, es handelt sich um zerstörte Requisiten), und NICHT, wenn Sie die Raw-Aktion aufrufen. Die Antwort von @GollyJer ist eine großartige Ergänzung und sollte dem ersten Teil dieser Antwort beigefügt werden. Alles in allem ist es sehr wahrscheinlich die beste Vorgehensweise.
Masse
1
Als Konvention bin ich versucht, nur $den Namen der Aktionen voranzustellen und die Kurzform mapDispatchToProps zu verwenden, aber ich habe $selbst bei jQuery immer ein wenig Jarring gefunden .
Kevin Dice
2
Ich verwende die Nummer 2, um die Variable neu zuzuweisen, wenn sie an connect () übergeben wird. Ich füge ein Aktionssuffix hinzu (dh setFilter ist setFilterAction). Vielen Dank für andere Optionen und Ihre Einblicke in jede dieser Optionen.
Kent
10

Eine fünfte Option:

5. Erlauben Sie eine bestimmte Ausnahme über eslintrcRegeln.

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

Warum?

Sie möchten kein variables Shadowing, können es aber in bestimmten Fällen nicht umgehen.

Warum nicht?

Sie möchten wirklich kein variables Shadowing in Ihrer Codebasis. 😝

GollyJer
quelle
6

Option Nummer sechs.

6. Deaktivieren Sie die Es-Lint-Regel für die bestimmte (n) Codezeile (n)

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

oder

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

Die zweite Möglichkeit, die Es-Lint-Regel vorübergehend zu deaktivieren, kann im Gegensatz zur ersten für mehrere Codezeilen verwendet werden. Es kann nützlich sein, wenn Sie mehr Argumente übergeben und diese in mehrere Codezeilen unterteilen.

Warum?

Dies ist eine einfache und geeignete Option für einige Anwendungsfälle (z. B. verwendet Ihr Team / Ihre Organisation bestimmte Es-Lint-Einstellungen und es wird davon abgeraten / verboten, diese Einstellungen zu ändern). Es deaktiviert den Es-Lint-Fehler in den Codezeilen, hat jedoch keinen Einfluss auf die mapDispatchToPropsSyntax und die Regel ist außerhalb der Codezeilen weiterhin vollständig aktiv.

Warum nicht?

Sie möchten nicht oder es ist Ihnen verboten, Ihren Code mit solchen Kommentaren aufzublähen. Sie wollen oder es ist Ihnen verboten, das Verhalten von Flusen zu beeinflussen.

bpalij
quelle
1

Option 7 ...

7. Verwenden Sie Behälterkomponenten

Warum?

Es ist ein bekanntes Muster und Sie erhalten den zusätzlichen Vorteil, dass Sie Ihre Komponenten vom Redux-Speicher entkoppeln, sodass sie leichter wiederverwendet werden können.

Warum nicht?

Sie benötigen jetzt zwei Dateien pro Komponente.

Wie?

// 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);
Bogdan Vitoc
quelle
Ein weiterer Punkt zu "Warum nicht": Es ist jetzt möglich, eine Komponente mit einem sehr ähnlichen Namen wie die beabsichtigte zu importieren, die nicht mit Redux verbunden ist.
Tao_oat
1

Ich habe 4. optimiert und erreicht, was ich Option 8 nennen möchte.

8. Importieren Sie Methoden unter einem anderen Namen

Warum?

Es hat die gleichen Vorteile wie das Importieren des gesamten Moduls, jedoch ohne Widerspruch zu anderen Regeln, z. B. Verwenden Sie keine Platzhalterimporte (Airbnb) .

Warum nicht?

Es wird eine unnötige Variablendeklaration hinzugefügt, die Verwirrung stiften kann.

Wie?

Für den Einzelmethodenfall

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

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

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

Mit der neuen Hooks-API in Version 7.1.0 können Sie die Variable entfernen und mapDispatchToPropsinsgesamt:

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;
Mark Dreyer
quelle