tutorial react example reactjs reactjs-flux

reactjs - example - Tener servicios en la aplicación React



react flux github (10)

El problema se vuelve extremadamente simple cuando te das cuenta de que un servicio angular es solo un objeto que ofrece un conjunto de métodos independientes del contexto. Es solo el mecanismo angular DI lo que lo hace ver más complicado. El DI es útil ya que se encarga de crear y mantener instancias para usted, pero realmente no lo necesita.

Considere una biblioteca AJAX popular llamada axios (de la que probablemente haya oído hablar):

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

¿No se comporta como un servicio? Proporciona un conjunto de métodos responsables de cierta lógica específica y es independiente del código principal.

Su caso de ejemplo fue sobre la creación de un conjunto aislado de métodos para validar sus entradas (por ejemplo, verificar la seguridad de la contraseña). Algunos sugirieron poner estos métodos dentro de los componentes, lo que para mí es claramente un antipatrón. ¿Qué sucede si la validación implica hacer y procesar llamadas de back-end de XHR o hacer cálculos complejos? ¿Combinaría esta lógica con controladores de clic del mouse y otras cosas específicas de la interfaz de usuario? Disparates. Lo mismo con el enfoque contenedor / HOC. ¿Está envolviendo su componente solo para agregar un método que verificará si el valor tiene un dígito? Venga.

Simplemente crearía un nuevo archivo llamado say ''ValidationService.js'' y lo organizaría de la siguiente manera:

const ValidationService = { firstValidationMethod: function(value) { //inspect the value }, secondValidationMethod: function(value) { //inspect the value } }; export default ValidationService;

Luego en su componente:

import ValidationService from "./services/ValidationService.js"; ... //inside the component yourInputChangeHandler(event) { if(!ValidationService.firstValidationMethod(event.target.value) { //show a validation warning return false; } //proceed }

Use este servicio desde cualquier lugar que desee. Si las reglas de validación cambian, debe centrarse solo en el archivo ValidationService.js.

Es posible que necesite un servicio más complicado que depende de otros servicios. En este caso, su archivo de servicio puede devolver un constructor de clase en lugar de un objeto estático para que pueda crear una instancia del objeto usted mismo en el componente. También puede considerar implementar un singleton simple para asegurarse de que siempre haya una sola instancia del objeto de servicio en uso en toda la aplicación.

Vengo del mundo angular donde podría extraer lógica a un servicio / fábrica y consumirlos en mis controladores.

Estoy tratando de entender cómo puedo lograr lo mismo en una aplicación React.

Digamos que tengo un componente que valida la entrada de contraseña del usuario (es fuerza). Su lógica es bastante compleja, por lo tanto, no quiero escribirla en el componente.

¿Dónde debo escribir esta lógica? ¿En una tienda si estoy usando flux? ¿O hay una mejor opción?


El servicio no se limita a Angular, incluso en Angular2 + ,

El servicio es solo una colección de funciones auxiliares ...

Y hay muchas formas de crearlos y reutilizarlos en la aplicación ...

1) Pueden ser todas las funciones separadas que se exportan desde un archivo js, ​​similar a la siguiente:

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

2) También podemos usar métodos de fábrica como, con la colección de funciones ... con ES6 puede ser una clase en lugar de un constructor de funciones:

class myService { constructor() { this._data = null; } setMyService(data) { this._data = data; } getMyService() { return this._data; } }

En este caso, necesita hacer una instancia con una nueva clave ...

const myServiceInstance = new myService();

También en este caso, cada instancia tiene su propia vida, así que tenga cuidado si desea compartirla, en ese caso debe exportar solo la instancia que desee ...

3) Si su función y utilidades no se compartirán, incluso puede ponerlos en el componente Reaccionar, en este caso, igual que la función en su componente reaccionar ...

class Greeting extends React.Component { getName() { return "Alireza Dezfoolian"; } render() { return <h1>Hello, {this.getName()}</h1>; } }

4) Otra forma de manejar las cosas, podría ser usar Redux , es una tienda temporal para usted, por lo que si lo tiene en su aplicación React , puede ayudarlo con muchas funciones getter setter que usa ... Es como una gran tienda que mantienen un registro de sus estados y pueden compartirlo entre sus componentes, por lo que pueden deshacerse de muchas molestias por las cosas que utilizamos en los servicios de captación y configuración

Siempre es bueno hacer un código DRY y no repetir lo que se debe usar para hacer que el código sea reutilizable y legible, pero no intente seguir formas angulares en la aplicación React , como se menciona en el elemento 4, usar Redux puede reducir su necesidad de servicios y limita su uso para algunas funciones auxiliares reutilizables como el elemento 1 ...


Estoy en la misma bota como tú. En el caso que mencione, implementaría el componente UI de validación de entrada como un componente React.

Estoy de acuerdo en que la implementación de la lógica de validación en sí misma no debe (debe) estar acoplada. Por lo tanto, lo pondría en un módulo JS separado.

Es decir, para la lógica que no debe acoplarse, use un módulo / clase JS en un archivo separado y use require / import para desacoplar el componente del "servicio".

Esto permite la inyección de dependencia y la prueba unitaria de los dos de forma independiente.


La misma situación: después de haber realizado múltiples proyectos angulares y pasar a Reaccionar, no tener una forma simple de proporcionar servicios a través de DI parece una pieza faltante (dejando a un lado los detalles del servicio).

Usando contexto y decoradores ES7 podemos acercarnos:

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

Parece que estos chicos lo han llevado un paso más allá / en una dirección diferente:

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

Todavía se siente como trabajar contra la corriente. Revisará esta respuesta dentro de 6 meses después de emprender un importante proyecto React.

EDITAR: Regresar 6 meses después con algo más de experiencia React. Considere la naturaleza de la lógica:

  1. ¿Está vinculado (solo) a la interfaz de usuario? Moverlo a un componente (respuesta aceptada).
  2. ¿Está vinculado (solo) a la gestión estatal? Muévelo a un thunk .
  3. Atado a ambos? Mover a un archivo separado, consumir en componentes a través de un selector y en thunks.

Algunos también HOCs para su reutilización, pero para mí lo anterior cubre casi todos los casos de uso. Además, considere escalar la administración del estado utilizando ducks para mantener las preocupaciones separadas y centradas en la interfaz de usuario estatal.


La primera respuesta no refleja el paradigma actual de Contenedor vs Presentador .

Si necesita hacer algo, como validar una contraseña, es probable que tenga una función que lo haga. Pasarías esa función a tu vista reutilizable como accesorio.

Contenedores

Entonces, la forma correcta de hacerlo es escribir un ValidatorContainer, que tendrá esa función como una propiedad, y envolver el formulario en él, pasando los accesorios correctos al niño. Cuando se trata de su vista, su contenedor de validación envuelve su vista y la vista consume la lógica de los contenedores.

La validación podría realizarse en las propiedades del contenedor, pero si está utilizando un validador de terceros o cualquier servicio de validación simple, puede usar el servicio como una propiedad del componente contenedor y usarlo en los métodos del contenedor. He hecho esto para componentes relajantes y funciona muy bien.

Proveedores

Si se necesita un poco más de configuración, puede usar un modelo de proveedor / consumidor. Un proveedor es un componente de alto nivel que se ajusta en algún lugar cerca y debajo del objeto superior de la aplicación (el que monta) y proporciona una parte de sí mismo, o una propiedad configurada en la capa superior, a la API de contexto. Luego configuro mis elementos contenedores para consumir el contexto.

Las relaciones de contexto padre / hijo no tienen que estar cerca una de la otra, solo el hijo tiene que descender de alguna manera. Las tiendas Redux y el React Router funcionan de esta manera. Lo he usado para proporcionar un contexto de descanso raíz para mis contenedores de descanso (si no proporciono el mío).

(nota: la API de contexto está marcada como experimental en los documentos, pero no creo que sea más, considerando lo que la está usando).

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

Middleware

Otra forma en que no lo he intentado, pero que he visto usado, es usar middleware junto con Redux. Defina su objeto de servicio fuera de la aplicación, o al menos, más alto que el almacén redux. Durante la creación de la tienda, inyecta el servicio en el middleware y el middleware maneja cualquier acción que afecte al servicio.

De esta manera, podría inyectar mi objeto restful.js en el middleware y reemplazar mis métodos de contenedor con acciones independientes. Todavía necesitaría un componente contenedor para proporcionar las acciones a la capa de vista de formulario, pero connect () y mapDispatchToProps me tienen cubierto allí.

El nuevo v4 react-router-redux utiliza este método para afectar el estado del historial, por ejemplo.

//Example middleware from react-router-redux //History is our service here and actions change it. import { CALL_HISTORY_METHOD } from ''./actions'' /** * This middleware captures CALL_HISTORY_METHOD actions to redirect to the * provided history object. This will prevent these actions from reaching your * reducer or any middleware that comes after this one. */ export default function routerMiddleware(history) { return () => next => action => { if (action.type !== CALL_HISTORY_METHOD) { return next(action) } const { payload: { method, args } } = action history[method](...args) } }


Necesitaba un poco de lógica de formateo para compartirla entre múltiples componentes y, como desarrollador de Angular, también se inclinó naturalmente hacia un servicio.

Compartí la lógica colocándola en un archivo separado

function format(input) { //convert input to output return output; } module.exports = { format: format };

y luego lo importó como un módulo

import formatter from ''../services/formatter.service''; //then in component render() { return formatter.format(this.props.data); }


También soy de Angular y estoy probando React, a partir de ahora, una forma recomendada (?) Parece estar usando HOCs :

Un componente de orden superior (HOC) es una técnica avanzada en React para reutilizar la lógica del componente. Los HOC no son parte de la API React, per se. Son un patrón que emerge de la naturaleza compositiva de React.

Supongamos que tiene input y área de textarea y desea aplicar la misma lógica de validación:

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

Luego escriba un HOC que valide y estilice el componente envuelto:

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} /> } } }

Ahora esos HOC comparten el mismo comportamiento de validación:

const InputWithValidator = withValidator(Input) const TextAreaWithValidator = withValidator(TextArea) render(( <div> <InputWithValidator /> <TextAreaWithValidator /> </div> ), document.getElementById(''root''));

Creé una demo simple.

Editar : otra demo está utilizando accesorios para pasar una variedad de funciones para que pueda compartir la lógica compuesta por múltiples funciones de validación en los HOC como:

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

Edit2 : React 16.8+ proporciona una nueva característica, Hook , otra buena forma de compartir lógica.

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


También vine del área de Angular.js y los servicios y las fábricas en React.js son más simples.

Puede usar funciones o clases simples, estilo de devolución de llamada y eventos Mobx como yo :)

// 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''s 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>

Aquí hay un ejemplo simple:


Tenga en cuenta que el propósito de React es unir mejor las cosas que lógicamente deberían combinarse. Si está diseñando un método complicado de "validar contraseña", ¿dónde se debe acoplar?

Bueno, tendrá que usarlo cada vez que el usuario necesite ingresar una nueva contraseña. Esto podría estar en la pantalla de registro, una pantalla de "contraseña olvidada", una pantalla de "restablecer contraseña para otro usuario" del administrador, etc.

Pero en cualquiera de esos casos, siempre estará vinculado a algún campo de entrada de texto. Así que ahí es donde debería estar acoplado.

Cree un componente React muy pequeño que consista únicamente en un campo de entrada y la lógica de validación asociada. Ingrese ese componente dentro de todos los formularios que podrían querer ingresar una contraseña.

Es esencialmente el mismo resultado que tener un servicio / fábrica para la lógica, pero lo está acoplando directamente a la entrada. Así que ahora nunca necesita decirle a esa función dónde buscar su entrada de validación, ya que está permanentemente unida.


o puede inyectar la herencia de clase "http" en React Component

a través de objetos de utilería.

  1. actualización:

    ReactDOM.render(<ReactApp data={app} />, document.getElementById(''root''));

  2. Simplemente edite React Component ReactApp de esta manera:

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