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

Имея услуги в приложении React

Я пришел из мира angular, где я мог извлечь логику в службу /factory и использовать их в моих контроллерах.

Я пытаюсь понять, как я могу добиться того же в приложении React.

Скажем, что у меня есть компонент, который проверяет ввод пароля пользователя (его силу). Эта логика довольно сложна, поэтому я не хочу писать ее в компоненте.

Где я должен писать эту логику? В магазине, если я использую флюс? Или есть лучший вариант?

4b9b3361

Ответ 1

Первый ответ не отражает текущую парадигму " Контейнер против презентатора".

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

Контейнеры

Таким образом, правильный способ сделать это - написать ValidatorContainer, который будет иметь эту функцию в качестве свойства, и обернуть форму в него, передав правильные реквизиты дочернему элементу. Когда дело доходит до вашего представления, ваш контейнер валидатора оборачивает ваше представление, и представление использует логику контейнеров.

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

Провайдеры

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

Контекстные отношения родитель/потомок не должны быть рядом друг с другом, просто ребенок должен быть каким-то образом спущен. Redux хранит и React Router функционирует таким образом. Я использовал его для предоставления корневого контекста для моих контейнеров отдыха (если я не предоставляю свой собственный).

(примечание: контекстный API помечен как экспериментальный в документах, но я не думаю, что это больше, учитывая, что его использует).

//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
	constructor(props){
		super(props);

		if(!("restful" in props)){
			throw Error("Restful service must be provided");
		}
	}

	getChildContext(){
		return {
			api: this.props.restful
		};
	}

	render() {
		return this.props.children;
	}
}

RestfulProvider.childContextTypes = {
	api: React.PropTypes.object
};

Ответ 2

Проблема становится чрезвычайно простой, когда вы понимаете, что служба Angular - это просто объект, который предоставляет набор независимых от контекста методов. Это просто механизм Angular DI, который делает его более сложным. DI полезен, поскольку он заботится о создании и поддержании экземпляров для вас, но вам это не нужно.

Рассмотрим популярную библиотеку AJAX с именем axios (о которой вы, вероятно, слышали):

import axios from "axios";
axios.post(...);

Разве это не ведет себя как услуга? Он предоставляет набор методов, отвечающих за определенную логику, и не зависит от основного кода.

В вашем примере речь шла о создании изолированного набора методов для проверки ваших входных данных (например, проверка надежности пароля). Некоторые предлагали поместить эти методы в компоненты, что для меня явно является анти-паттерном. Что если проверка включает в себя выполнение и обработку внутренних вызовов XHR или выполнение сложных вычислений? Вы бы смешали эту логику с обработчиками щелчков мыши и другими специфическими элементами пользовательского интерфейса? Ерунда. То же самое с подходом контейнер /HOC. Обернуть ваш компонент только для добавления метода, который проверит, есть ли в значении цифра? Давай.

Я бы просто создал новый файл с именем скажем "ValidationService.js" и организовал его следующим образом:

const ValidationService = {
    firstValidationMethod: function(value) {
        //inspect the value
    },

    secondValidationMethod: function(value) {
        //inspect the value
    }
};

export default ValidationService;

Тогда в вашем компоненте:

import ValidationService from "./services/ValidationService.js";

...

//inside the component
yourInputChangeHandler(event) {

    if(!ValidationService.firstValidationMethod(event.target.value) {
        //show a validation warning
        return false;
    }
    //proceed
}

Используйте этот сервис из любой точки мира. Если правила проверки изменятся, вам нужно сосредоточиться только на файле ValidationService.js.

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

Ответ 3

Имейте в виду, что цель Реагента состоит в том, чтобы лучше сочетать вещи, которые логически должны быть связаны. Если вы разрабатываете сложный метод "проверять пароль", где он должен быть связан?

Ну, вам нужно будет использовать его каждый раз, когда пользователю нужно ввести новый пароль. Это может быть на экране регистрации, экране "забытый пароль", экране администратора "reset для другого пользователя" и т.д.

Но в любом из этих случаев он всегда будет привязан к некоторому текстовому полю ввода. Так что там, где он должен быть связан.

Создайте очень маленький компонент React, который состоит исключительно из поля ввода и связанной логики проверки. Введите этот компонент во все формы, которые могут потребовать ввода пароля.

Это по сути тот же результат, что и для службы / factory для логики, но вы связываете его непосредственно со входом. Таким образом, вам теперь не нужно указывать эту функцию, где искать вход для проверки, поскольку он постоянно связан.

Ответ 4

Мне нужна была некоторая логика форматирования для нескольких компонентов, и как разработчик Angular также склонялся к сервису.

Я поделился логикой, поместив ее в отдельный файл

function format(input) {
    //convert input to output
    return output;
}

module.exports = {
    format: format
};

а затем импортировать его как модуль

import formatter from '../services/formatter.service';

//then in component

    render() {

        return formatter.format(this.props.data);
    }

Ответ 5

Та же ситуация: после выполнения нескольких проектов Angular и перехода на React, не имея простого способа предоставления услуг через DI, это кажется отсутствующим элементом (не обращая внимания на особенности сервиса).

Используя контекст и ES7-декораторы, мы можем приблизиться:

https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/

Кажется, эти ребята сделали еще один шаг в другом направлении:

http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs

Все еще хочется работать против зерна. Я вернусь к этому ответу через 6 месяцев после проведения крупного проекта React.

РЕДАКТИРОВАТЬ: Вернуться через 6 месяцев с еще немного опыта React. Рассмотрим природу логики:

  1. Это связано (только) с пользовательским интерфейсом? Переместить его в компонент (принятый ответ).
  2. Это связано (только) с государственным управлением? Переместите это в гром.
  3. Привязан к обоим? Переместить в отдельный файл, использовать в компоненте через селектор и в thunks.

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

Ответ 6

Я также пришел из области Angular.js, а сервисы и фабрики в React.js более простые.

Вы можете использовать простые функции или классы, стиль обратного вызова и событие Mobx, как я :)

// Here we have Service class > dont forget that in JS class is Function
class HttpService {
  constructor() {
    this.data = "Hello data from HttpService";
    this.getData = this.getData.bind(this);
  }

  getData() {
    return this.data;
  }
}


// Making Instance of class > it object now
const http = new HttpService();


// Here is React Class extended By React
class ReactApp extends React.Component {
  state = {
    data: ""
  };

  componentDidMount() {
    const data = http.getData();

    this.setState({
      data: data
    });
  }

  render() {
    return <div>{this.state.data}</div>;
  }
}

ReactDOM.render(<ReactApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

</body>
</html>

Ответ 7

Я тоже из Angular и пробую React, на данный момент, один рекомендуемый (?) Способ, кажется, использует компоненты высокого порядка:

Компонент высшего порядка (HOC) - это продвинутая техника в React для повторного использования логики компонента. По сути, HOC не являются частью React API. Они являются образцом, который вытекает из композиционной природы Reacts.

Допустим, у вас есть input и textarea и вам нравится применять ту же логику проверки:

const Input = (props) => (
  <input type="text"
    style={props.style}
    onChange={props.onChange} />
)
const TextArea = (props) => (
  <textarea rows="3"
    style={props.style}
    onChange={props.onChange} >
  </textarea>
)

Затем напишите HOC, который проверяет и обрабатывает обернутый компонент:

function withValidator(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props)

      this.validateAndStyle = this.validateAndStyle.bind(this)
      this.state = {
        style: {}
      }
    }

    validateAndStyle(e) {
      const value = e.target.value
      const valid = value && value.length > 3 // shared logic here
      const style = valid ? {} : { border: '2px solid red' }
      console.log(value, valid)
      this.setState({
        style: style
      })
    }

    render() {
      return <WrappedComponent
        onChange={this.validateAndStyle}
        style={this.state.style}
        {...this.props} />
    }
  }
}

Теперь эти HOC имеют одинаковое проверочное поведение:

const InputWithValidator = withValidator(Input)
const TextAreaWithValidator = withValidator(TextArea)

render((
  <div>
    <InputWithValidator />
    <TextAreaWithValidator />
  </div>
), document.getElementById('root'));

Я создал простую демонстрацию.

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

<InputWithValidator validators={[validator1,validator2]} />
<TextAreaWithValidator validators={[validator1,validator2]} />

Edit2: React 16. 8+ предоставляет новую функцию, Hook, еще один хороший способ поделиться логикой.

const Input = (props) => {
  const inputValidation = useInputValidation()

  return (
    <input type="text"
    {...inputValidation} />
  )
}

function useInputValidation() {
  const [value, setValue] = useState('')
  const [style, setStyle] = useState({})

  function handleChange(e) {
    const value = e.target.value
    setValue(value)
    const valid = value && value.length > 3 // shared logic here
    const style = valid ? {} : { border: '2px solid red' }
    console.log(value, valid)
    setStyle(style)
  }

  return {
    value,
    style,
    onChange: handleChange
  }
}

https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js

Ответ 8

Сервис не ограничен Angular, даже в Angular2+,

Сервис - это просто набор вспомогательных функций...

И есть много способов их создания и повторного использования в приложении...

1) Все они могут быть отдельными функциями, которые экспортируются из файла js, как показано ниже:

export const firstFunction = () => {
   return "firstFunction";
}

export const secondFunction = () => {
   return "secondFunction";
}
//etc

2) Мы также можем использовать фабричный метод, например, с набором функций... в ES6 это может быть класс, а не конструктор функции:

class myService {

  constructor() {
    this._data = null;
  }

  setMyService(data) {
    this._data = data;
  }

  getMyService() {
    return this._data;
  }

}

В этом случае вам нужно сделать экземпляр с новым ключом...

const myServiceInstance = new myService();

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

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

class Greeting extends React.Component {
  getName() {
    return "Alireza Dezfoolian";
  }

  render() {
    return <h1>Hello, {this.getName()}</h1>;
  }
}

4) Другим способом, с помощью которого вы можете обрабатывать вещи, может быть использование Redux, это временное хранилище для вас, поэтому, если у вас есть это в вашем приложении React, оно может помочь вам со многими функциями геттер-сеттера, которые вы используете... Это как большой магазин которые следят за вашими состояниями и могут делиться ими между вашими компонентами, чтобы избавить вас от многих неприятностей, связанных с установщиками-установщиками, которые мы используем в сервисах...

Всегда полезно делать СУХОЙ код и не повторять то, что нужно использовать, чтобы сделать код многократно используемым и читабельным, но не пытайтесь следовать угловым путям в приложении React, как упоминалось в пункте 4, использование Redux может снизить ваши потребности сервисы, и вы ограничиваете их использование для некоторых повторно используемых вспомогательных функций, таких как пункт 1...

Ответ 9

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

Я согласен, что сама реализация логики проверки должна (должна) не соединяться. Поэтому я бы поставил его в отдельный JS-модуль.

То есть для логики, которая не должна быть связана, используйте JS-модуль/класс в отдельном файле и используйте require/import, чтобы отделить компонент от "службы".

Это позволяет осуществлять инъекцию зависимостей и единичное тестирование двух независимо.

Ответ 10

или вы можете ввести наследование класса "http" в React Component

через объект подпорки.

  1. Обновить:

    ReactDOM.render(<ReactApp data={app} />, document.getElementById('root'));
    
  2. Просто отредактируйте React Component ReactApp следующим образом:

    class ReactApp extends React.Component {
    
    state = {
    
        data: ''
    
    }
    
        render(){
    
        return (
            <div>
            {this.props.data.getData()}      
            </div>
    
        )
        }
    }
    

Ответ 11

Использование метода DRY поможет вам написать лучший код в ReactJS. На самом деле ReactJS делает интерфейс более интерактивным. Он поддерживает безболезненный переход каждый раз, когда происходит обновление, просто изменяя изменения, а не повторяя весь процесс снова. Это помогает в более легкой отладке и более предсказуемом коде в целом. Этот блог, посвященный 7 преимуществам ReactJS для создания интерактивных пользовательских интерфейсов, поможет вам лучше понять вещи.