Modo corretto per condividere le funzioni tra i componenti in React


92

Ho più componenti che devono tutti fare la stessa cosa. (Una semplice funzione che mappa sui loro componenti figlio e fa qualcosa su ciascuno di essi). Al momento sto definendo questo metodo in ciascuno dei componenti. Ma voglio definirlo solo una volta.

Potrei definirlo nel componente di primo livello e poi tramandarlo come sostegno. Ma non sembra del tutto corretto. È più una funzione di libreria che un oggetto di scena. (Mi sembra).

Qual è il modo corretto di farlo?


Dai un'occhiata a questo link . Oppure cerca "mixin" e "HOC" su Google.
Borzh

Risposte:


38

Se usi qualcosa come browserify , puoi avere un file esterno, ad esempio util.js, che esporta alcune funzioni di utilità.

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

exports.doSomething = doSomething;

Quindi richiedilo secondo necessità

var doSomething = require('./util.js').doSomething;

@AnkitSinghaniya Dipende, cosa usi per gestire lo stato del front-end della tua app?
deowk

1
Sto usando gli stati di reazione.
AKS

Perché ricevo "doSomething" non definito senza alcuna idea?
Abhijit Chakra

48

Utils.js con la più recente sintassi Javascript ES6

Crea il Utils.jsfile in questo modo con più funzioni, ecc

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

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

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

Quindi nei componenti che si desidera utilizzare le funzioni util, importare le funzioni specifiche necessarie. Non devi importare tutto

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

Quindi usa queste funzioni all'interno del componente in questo modo:

justAnAlert();
<p>{doSomethingWithInput('hello')}</p>

1
A cosa serve la /filefine della riga di importazione?
alex

@alex È solo un esempio. Metti lì il tuo percorso relativo a util.js
Fangming

14

Se vuoi manipolare lo stato nelle funzioni di supporto, segui questo:

  1. Crea un file Helpers.js:

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

  2. Importa la funzione di supporto nel file del componente:

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

  3. Nel tuo costruttore aggiungi quella funzione di supporto alla classe

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

  4. Nella tua funzione di rendering usalo:

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


10

Ecco alcuni esempi su come riutilizzare una funzione ( FetchUtil.handleError) in un componente React ( App).

Soluzione 1: utilizzo della sintassi del modulo CommonJS

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

Soluzione 2: utilizzo di "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;

Nota: se stai usando React v15.4 (o precedente) devi importare createClasscome segue:

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

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

Component (che riutilizza FetchUtil)

componenti / 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;

7

Un'altra valida opzione oltre alla creazione di un file util sarebbe quella di utilizzare un componente di ordine superiore per creare un withComponentMapper()wrapper. Questo componente accetta un componente come parametro e lo restituisce con la componentMapper()funzione tramandata come prop.

Questa è considerata una buona pratica in React. Puoi scoprire come farlo in dettaglio qui.


Sono curioso di sapere perché React scoraggia l'ereditarietà dei componenti dove il pattern withComponent sembra essere simile?
Workwise

@Wor Usando l'ereditarietà si intendono le due componenti
Jake

4

Sembra una funzione di utilità, in tal caso perché non inserirla in un modulo di utilità statico separato?

Altrimenti se usi un transpiler come Babel puoi usare i metodi statici di es7:

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

Oppure se stai usando React.createClass puoi usare l' oggetto statics :

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

Tuttavia non consiglio queste opzioni, non ha senso includere un componente per un metodo di utilità.

Inoltre, non dovresti passare un metodo a tutti i tuoi componenti come sostegno, li accoppierà strettamente e renderà il refactoring più doloroso. Consiglio un semplice vecchio modulo di utilità.

L'altra opzione è usare un mixin per estendere la classe, ma non lo consiglio perché non puoi farlo in es6 + (e in questo caso non vedo il vantaggio).


Le informazioni sui mixin sono utili. In questo caso, desidero utilizzare la funzione in modo condizionale anziché fare in modo che qualcosa accada automaticamente in un evento del ciclo di vita. Così. Come dici tu, una semplice vecchia funzione di utilità è la strada da percorrere.

1
Nota: React.createClassè deprecato da React 15.5.0. create-react-app suggerisce invece di utilizzare il modulo npm create-react-class.
Alex Johnson

Sto cercando di fare la stessa cosa dell'OP ma sono un po 'confuso qui. Non consigli nessuna delle opzioni che elenchi. Cosa mi consigliate?
kkuilla

Vorrei semplicemente creare un file per la funzione doSomething.js, ad esempio , o un file con più funzioni di "utilità" simili, ad esempio utils.jse importare quelle funzioni in cui è necessario utilizzarle
Dominic

4

Mostrerò due stili di seguito e dovrai scegliere in base a quanto la logica dei componenti è correlata tra loro.

Stile 1 - È possibile creare componenti relativamente correlati con riferimenti di richiamata, come questo, in ./components/App.js...

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

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

E poi puoi usare le funzioni condivise tra di loro in questo modo ...

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

Stile 2 - I componenti di tipo Util possono essere creati in questo modo, in ./utils/time.js...

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

E poi possono essere usati in questo modo, 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"));
    }
}

Quale usare?

Se la logica è relativamente correlata (vengono utilizzati solo insieme nella stessa app), è necessario condividere gli stati tra i componenti. Ma se la tua logica è lontanamente correlata (cioè, matematica util, util di formattazione del testo), allora dovresti creare e importare funzioni di classe util.


2

Non dovresti usare un Mixin per questo? Vedi https://facebook.github.io/react/docs/reusable-components.html

Anche se stanno cadendo in disgrazia, vedere https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

Potrebbe essere utile


Sono d'accordo che mixin è una soluzione migliore qui rispetto alla semplice esportazione di una funzione comune.
Tao Huang

@TaoHuang Alcune cose da considerare, 1. I mix non sono a prova di futuro e verranno utilizzati sempre meno nelle app moderne, 2. L'uso di una funzione esportata rende il tuo framework di codice agnostico: potresti facilmente usare quelle funzioni su qualsiasi altro progetto js. Leggi anche questo post sul perché NON usare Mixin -> facebook.github.io/react/blog/2016/07/13/…
deowk

Un mixin può accedere e modificare lo stato, mentre un tratto no, e poiché l'OP sta dicendo che vuole qualcosa da trattare come una libreria di funzioni, un mixin non sarebbe la soluzione giusta.
HoldOffHunger

Per aggiornarlo, utilizzare le funzioni di ordine superiore. facebook.github.io/react/docs/higher-order-components.html
Davet

Il primo collegamento è morto
alex
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.