Richtige Methode zum Teilen von Funktionen zwischen Komponenten in React

89

Ich habe mehrere Komponenten, die alle dasselbe tun müssen. (Eine einfache Funktion, die ihre untergeordneten Komponenten abbildet und jedem etwas antut). Im Moment definiere ich diese Methode in jeder der Komponenten. Aber ich möchte es nur einmal definieren.

Ich könnte es in der obersten Komponente definieren und es dann als Requisite weitergeben. Das fühlt sich aber nicht ganz richtig an. Es ist eher eine Bibliotheksfunktion als eine Requisite. (Es kommt mir vor).

Was ist der richtige Weg, dies zu tun?


quelle
Schauen Sie sich diesen Link an . Oder suchen Sie in Google nach "mixins" und "HOC".
Borzh

Antworten:

35

Wenn Sie so etwas wie browserify verwenden , können Sie eine externe Datei haben, dh util.js, die einige Dienstprogrammfunktionen exportiert.

var doSomething = function(num) {
 return num + 1;
}

exports.doSomething = doSomething;

Dann benötigen Sie es nach Bedarf

var doSomething = require('./util.js').doSomething;
deowk
quelle
@AnkitSinghaniya Das hängt davon ab, was Sie verwenden, um den Front-End-Status Ihrer App zu verwalten.
Deowk
1
Ich benutze Reaktionszustände.
Aks
Warum ich "doSomething" bekomme, ist keine Idee definiert.
Abhijit Chakra
45

Utils.js mit der neuesten Javascript ES6-Syntax

Erstellen Sie die Utils.jsDatei wie folgt mit mehreren Funktionen usw.

const someCommonValues = ['common', 'values'];

export const doSomethingWithInput = (theInput) => {
   //Do something with the input
   return theInput;
};

export const justAnAlert = () => {
   alert('hello');
};

Importieren Sie dann in Ihren Komponenten, für die Sie die util-Funktionen verwenden möchten, die spezifischen Funktionen, die benötigt werden. Sie müssen nicht alles importieren

import {doSomethingWithInput, justAnAlert} from './path/to/utils.js/file'

Verwenden Sie dann diese Funktionen innerhalb der Komponente wie folgt:

justAnAlert();
<p>{doSomethingWithInput('hello')}</p>
Fangming
quelle
Wofür steht das /fileam Ende der Importzeile?
Alex
@alex Es ist nur ein Beispiel. Geben Sie dort Ihren relativen Pfad zu util.js ein
Fangming
13

Wenn Sie den Status in Hilfsfunktionen ändern möchten, gehen Sie wie folgt vor:

  1. Erstellen Sie eine Helpers.js-Datei:

    export function myFunc(){ return this.state.name; //define it according to your needs }

  2. Importieren Sie die Hilfsfunktion in Ihre Komponentendatei:

    import {myFunc} from 'path-to/Helpers.js'

  3. Fügen Sie in Ihrem Konstruktor diese Hilfsfunktion zur Klasse hinzu

    constructor(){ this.myFunc = myFunc.bind(this) }

  4. Verwenden Sie in Ihrer Renderfunktion Folgendes:

    render(){ <div>{this.myFunc()}</div> }

Jaskaran Singh
quelle
9

Hier einige Beispiele, wie Sie eine Funktion ( FetchUtil.handleError) in einer React-Komponente ( App) wiederverwenden können .

Lösung 1: Verwenden der CommonJS-Modulsyntax

module.exports = {
  handleError: function(response) {
    if (!response.ok) throw new Error(response.statusText);
    return response;
  },
};

Lösung 2: Verwenden von "createClass" (React v16)

util / FetchUtil.js

const createReactClass = require('create-react-class');

const FetchUtil = createReactClass({
  statics: {
    handleError: function(response) {
      if (!response.ok) throw new Error(response.statusText);
      return response;
    },
  },
  render() {
  },
});

export default FetchUtil;

Hinweis: Wenn Sie React v15.4 (oder niedriger) verwenden, müssen Sie Folgendes importieren createClass:

import React from 'react';
const FetchUtil = React.createClass({});

Quelle: https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass

Komponente (die FetchUtil wiederverwendet)

Komponenten / App.jsx

import Categories from './Categories.jsx';
import FetchUtil from '../utils/FetchUtil';
import Grid from 'material-ui/Grid';
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {categories: []};
  }

  componentWillMount() {
    window
      .fetch('/rest/service/v1/categories')
      .then(FetchUtil.handleError)
      .then(response => response.json())
      .then(categories => this.setState({...this.state, categories}));
  }

  render() {
    return (
      <Grid container={true} spacing={16}>
        <Grid item={true} xs={12}>
          <Categories categories={this.state.categories} />
        </Grid>
      </Grid>
    );
  }
}

export default App;
Benny Neugebauer
quelle
7

Eine andere solide Option außer dem Erstellen einer Util-Datei wäre die Verwendung einer Komponente höherer Ordnung zum Erstellen eines withComponentMapper()Wrappers. Diese Komponente würde eine Komponente als Parameter aufnehmen und mit dem zurückgebencomponentMapper() als Requisite übergebenen Funktion zurück.

Dies wird in React als bewährte Methode angesehen. Wie das geht, erfahren Sie hier im Detail.

Jake
quelle
Ich bin gespannt, warum React von der Vererbung von Komponenten abhält, wenn das withComponent-Muster ähnlich zu sein scheint.
Arbeitsweise
@Wor Verwendung der Vererbung bedeutet die beiden Komponenten
Jake
4

Klingt nach einer Utility-Funktion. In diesem Fall sollten Sie sie in ein separates statisches Utility-Modul einfügen.

Andernfalls können Sie bei Verwendung eines Transpilers wie Babel die statischen Methoden von es7 verwenden:

class MyComponent extends React.Component {
  static someMethod() { ...

Wenn Sie React.createClass verwenden, können Sie auch das statische Objekt verwenden:

var MyComponent = React.createClass({
  statics: {
    customMethod: function(foo) {
      return foo === 'bar';
    }
  }

Ich rate jedoch nicht zu diesen Optionen. Es ist nicht sinnvoll, eine Komponente für eine Dienstprogrammmethode einzuschließen.

Außerdem sollten Sie keine Methode als Requisite durch alle Ihre Komponenten weitergeben, da dies sie eng koppelt und das Refactoring schmerzhafter macht. Ich empfehle ein einfaches altes Utility-Modul.

Die andere Möglichkeit besteht darin, ein Mixin zu verwenden, um die Klasse zu erweitern, aber ich empfehle dies nicht, da Sie dies in es6 + nicht tun können (und ich sehe den Vorteil in diesem Fall nicht).

Dominic
quelle
Die Informationen zu Mixins sind nützlich. In diesem Fall möchte ich die Funktion bedingt verwenden, anstatt dass bei einem Lebenszyklusereignis automatisch etwas passiert. Damit. Wie Sie sagen, ist eine einfache alte Dienstprogrammfunktion der richtige Weg.
1
Hinweis: React.createClassist seit React 15.5.0 veraltet. create-react-app schlägt create-react-classstattdessen die Verwendung des npm-Moduls vor.
Alex Johnson
Ich möchte das Gleiche tun wie das OP, bin aber hier etwas verwirrt. Sie empfehlen keine der von Ihnen aufgelisteten Optionen. Was Sie empfehlen Sie?
Kkuilla
Ich würde einfach eine Datei für die Funktion erstellen, z. B. doSomething.jseine Datei mit mehreren ähnlichen "Dienstprogramm" -Funktionen, z. B. utils.jsund die Funktionen dort importieren, wo Sie sie verwenden müssen
Dominic
4

Im Folgenden werden zwei Stile gezeigt, und Sie sollten auswählen, in welchem ​​Verhältnis die Logik der Komponenten zueinander steht.

Style 1 - Relativ bezogenen Komponenten werden können erstellt mit Callback - Referenzen, wie diese, in ./components/App.js...

<SomeItem
    ref={(instance) => {this.childA = instance}}
/>

<SomeOtherItem
    ref={(instance) => {this.childB = instance}}
/>

Und dann können Sie verwenden gemeinsam genutzte Funktionen zwischen ihnen so ...

this.childA.investigateComponent(this.childB);  // call childA function with childB as arg
this.childB.makeNotesOnComponent(this.childA);  // call childB function with childA as arg

Stil 2 - Util-Komponenten können wie folgt erstellt werden./utils/time.js :

export const getTimeDifference = function (start, end) {
    // return difference between start and end
}

Und dann können sie so verwendet werden , in ./components/App.js...

import React from 'react';
import {getTimeDifference} from './utils/time.js';

export default class App extends React.Component {
    someFunction() {
        console.log(getTimeDifference("19:00:00", "20:00:00"));
    }
}

Welche verwenden?

Wenn die Logik relativ verwandt ist (sie werden nur in derselben App zusammen verwendet), sollten Sie Zustände zwischen Komponenten teilen. Wenn Ihre Logik jedoch entfernt verwandt ist (z. B. Math Util, Text Formatierungs Util), sollten Sie Util-Klassenfunktionen erstellen und importieren.

HoldOffHunger
quelle
2

Solltest du dafür kein Mixin verwenden? Siehe https://facebook.github.io/react/docs/reusable-components.html

Obwohl sie in Ungnade fallen, siehe https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

Könnte nützlich sein

Davet
quelle
Ich stimme zu, dass Mixin hier eine bessere Lösung ist, als nur eine gemeinsame Funktion zu exportieren.
Tao Huang
@TaoHuang Einige Dinge zu beachten: 1.Mixins sind nicht zukunftssicher und werden in modernen Apps immer weniger verwendet. 2. Die Verwendung einer exportierten Funktion macht Ihr Code-Framework agnostisch - Sie können diese Funktion problemlos für jedes andere js-Projekt verwenden. Lesen Sie auch diesen Beitrag darüber, warum Sie Mixins NICHT verwenden sollten -> facebook.github.io/react/blog/2016/07/13/…
deowk
Ein Mixin kann auf den Status zugreifen und diesen ändern, während ein Merkmal dies nicht tut. Da das OP angibt, dass etwas als Funktionsbibliothek behandelt werden soll, wäre ein Mixin nicht die richtige Lösung.
HoldOffHunger
Verwenden Sie zum Aktualisieren Funktionen höherer Ordnung. facebook.github.io/react/docs/higher-order-components.html
Davet
Erster Link ist tot
Alex