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?
reactjs
reactjs-flux
Dennis Nerush
fuente
fuente
Respuestas:
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. Estaría pasando esa función a su 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 se puede hacer todo 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).
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.
fuente
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):
¿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 XHR o hacer cálculos complejos? ¿Mezclarías esta lógica con los controladores de clic del mouse y otras cosas específicas de la interfaz de usuario? Disparates. Lo mismo con el enfoque contenedor / HOC. ¿Está ajustando 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:
Luego en su componente:
Use este servicio desde cualquier lugar que desee. Si las reglas de validación cambian, debe centrarse únicamente 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.
fuente
Necesitaba un poco de lógica de formato para compartir 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
y luego lo importó como un módulo
fuente
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.
fuente
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 :)
Aquí hay un ejemplo simple:
fuente
La misma situación: después de haber realizado múltiples proyectos angulares y pasar a Reaccionar, no tener una manera simple de proporcionar servicios a través de DI parece una pieza faltante (dejando de 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 muchachos 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: Volver 6 meses después con algo más de experiencia React. Considere la naturaleza de la lógica:
Algunos también buscan HOC 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 patos para mantener las preocupaciones separadas y centradas en la interfaz de usuario estatal.
fuente
Yo también soy de Angular y estoy probando React, a partir de ahora, una forma recomendada (?) Parece estar usando Componentes de alto orden :
Digamos que tiene
input
y letextarea
gusta aplicar la misma lógica de validación:Luego escriba un HOC que valide y estilice el componente envuelto:
Ahora esos HOC comparten el mismo comportamiento de validación:
Creé una demostración simple .
Editar : otra demostración está utilizando accesorios para pasar una serie de funciones para que pueda compartir la lógica compuesta por múltiples funciones de validación en
HOC
s como:Edit2 : React 16.8+ proporciona una nueva característica, Hook , otra buena forma de compartir lógica.
https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js
fuente
HOC
, vea mi edición para otra demostració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:
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:
En este caso necesita hacer una instancia con nueva clave ...
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 ...
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 hacen un seguimiento de sus estados y pueden compartirlo entre sus componentes, por lo que pueden deshacerse de muchas molestias por las cosas de getter setter que usamos en los servicios ...
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 ...
fuente
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.
fuente
o puede inyectar la herencia de clase "http" en React Component
a través de objetos de utilería.
actualización:
Simplemente edite React Component ReactApp de esta manera:
fuente
Bueno, el patrón más utilizado para la lógica reutilizable que he encontrado es escribir un gancho o crear un archivo de utilidades. Depende de lo que quieras lograr.
Por ejemplo, si desea validar datos de formulario, crearía un enlace personalizado llamado useForm.js y le proporcionaría datos de formulario y, a cambio, me devolvería un objeto que contiene dos cosas:
Definitivamente puedes devolver más cosas a medida que progresas.
Otro ejemplo sería como si quisiera extraer alguna información de una URL y luego crearía un archivo de utilidades que contenga una función e importarla donde sea necesario:
fuente