Подтвердить что ты не робот

Правильный способ обмена функциями между компонентами в React

У меня есть несколько компонентов, которые все должны делать то же самое. (Простая функция, которая отображает их дочерние компоненты и делает что-то для каждого). В настоящий момент я определяю этот метод в каждом из компонентов. Но я только хочу определить его один раз.

Я мог бы определить его в компоненте верхнего уровня, а затем передать его как опору. Но это не совсем правильно. Это скорее функция библиотеки, чем поддержка. (Мне кажется).

Каков правильный способ сделать это?

4b9b3361

Ответ 1

Если вы используете что-то вроде browserify, вы можете иметь внешний файл i.e util.js, который экспортирует некоторые служебные функции.

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

exports.doSomething = doSomething;

Затем требуйте его при необходимости

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

Ответ 2

Utils.js с последним синтаксисом Javascript ES6

Создайте файл Utils.js, например, с несколькими функциями и т.д.

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

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

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

Затем в ваших компонентах, для которых вы хотите использовать функции util, импортируйте нужные функции. Вам не нужно импортировать все

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

А затем используйте эти функции внутри компонента следующим образом:

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

Ответ 3

Вот несколько примеров того, как вы можете повторно использовать функцию (FetchUtil.handleError) в компоненте React (App).

Решение 1. Использование синтаксиса модуля CommonJS

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

Решение 2. Использование 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;

Примечание. Если вы используете React v15.4 (или ниже), вам нужно импортировать createClass следующим образом:

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

Источник: https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass

Компонент (который использует FetchUtil)

компоненты/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;

Ответ 4

Другой надежный вариант, кроме создания файла утилит, заключается в использовании компонента более высокого порядка для создания оболочки withComponentMapper(). Этот компонент будет принимать компонент в качестве параметра и возвращать его обратно с помощью функции componentMapper(), переданной в качестве реквизита.

Это считается хорошей практикой в React. Вы можете узнать, как это сделать, подробно здесь.

Ответ 5

Если вы хотите манипулировать состоянием в вспомогательных функциях, выполните следующие действия:

  1. Создайте файл Helpers.js:

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

  2. Импортируйте вспомогательную функцию в файл компонента:

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

  3. В своем конструкторе добавьте эту вспомогательную функцию в класс

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

  4. В вашей функции рендеринга используйте его:

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

Ответ 6

Звучит как служебная функция, в этом случае почему бы не поместить ее в отдельный статический служебный модуль?

В противном случае, если вы используете транспилер вроде Babel, вы можете использовать статические методы es7:

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

Или, если вы используете React.createClass, вы можете использовать объект statics:

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

Однако я не рекомендую эти параметры, нет смысла включать компонент для метода утилиты.

Кроме того, вы не должны передавать метод через все ваши компоненты в качестве опоры, которые будут тесно связаны с ними и сделать рефакторинг более болезненным. Я советую простой старый служебный модуль.

Другой вариант - использовать mixin для расширения класса, но я не рекомендую это делать, поскольку вы не можете сделать это в es6 + (и я не вижу преимущества в этом случае).

Ответ 7

Это зависит от того, насколько логика компонентов связана друг с другом.

Если логика относительно связана (они используются вместе только в одном приложении), то вы должны делить состояния между компонентами. Но если ваша логика имеет отдаленное отношение (например, математическая утилита, текстовая утилита), то вам следует создавать и импортировать функции класса утилит.

Относительно связанные компоненты могут быть созданы со ссылками обратного вызова, как это, в ./components/App.js...

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

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

И тогда вы можете использовать общие функции между ними, как это...

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

Компоненты типа Util могут быть созданы следующим образом, в ./utils/time.js...

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

И тогда их можно использовать вот так, в ./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"));
    }
}