Estaba mirando un tutorial sobre React Hooks y en el tutorial el autor creó un useDropdown hook para renderizar menús desplegables reutilizables. el codigo es asi
import React, { useState } from "react"; const useDropdown = (label, defaultState, options) => { const [state, updateState] = useState(defaultState); const id = `use-dropdown-${label.replace(" ", "").toLowerCase()}`; const Dropdown = () => ( <label htmlFor={id}> {label} <select id={id} value={state} onChange={e => updateState(e.target.value)} onBlur={e => updateState(e.target.value)} disabled={!options.length} > <option /> {options.map(item => ( <option key={item} value={item}> {item} </option> ))} </select> </label> ); return [state, Dropdown, updateState]; }; export default useDropdown;y usó esto en un componente como este
import React, { useState, useEffect } from "react"; import useDropdown from "./useDropdown"; const SomeComponent = () => { const [animal, AnimalDropdown] = useDropdown("Animal", "dog", ANIMALS); const [breed, BreedDropdown, updateBreed] = useDropdown("Breed", "", breeds); return ( <div className="search-params"> <form> <label htmlFor="location"> Location <input id="location" value={location} placeholder="Location" onChange={e => updateLocation(e.target.value)} /> </label> <AnimalDropdown /> <BreedDropdown /> <button>Submit</button> </form> </div> ); }; export default SomeComponent; Dijo que de esta manera podemos crear componentes desplegables reutilizables. Me preguntaba en qué se diferencia esto de definir un componente Dropdown simple y antiguo y pasarle accesorios. La única diferencia que se me ocurre en este caso es que ahora tenemos la capacidad de obtener el estado y establecer el estado en el componente principal (es decir SomeComponent ) y leer/establecer el estado del elemento secundario (es decir, la salida del componente mediante useDropdown ) directamente desde allí. Sin embargo, ¿se considera esto un antipatrón ya que estamos rompiendo el flujo de datos unidireccional?
Si bien no existe una restricción estricta sobre cómo debe definir ganchos personalizados y qué lógica debe contener, es un antipatrón para escribir ganchos que devuelven JSX
Debe evaluar qué beneficios le brinda cada enfoque y luego decidir sobre una pieza de código en particular
Hay algunas desventajas de usar ganchos para devolver JSX
useMemo , que no le brinda la flexibilidad de una función de comparación personalizada como React.memoEl beneficio, por otro lado, es que tiene control sobre el estado del componente en el padre. Sin embargo, aún puede implementar la misma lógica utilizando un enfoque de componente controlado
import React, { useState } from "react"; const Dropdown = Reat.memo((props) => { const { label, value, updateState, options } = props; const id = `use-dropdown-${label.replace(" ", "").toLowerCase()}`; return ( <label htmlFor={id}> {label} <select id={id} value={value} onChange={e => updateState(e.target.value)} onBlur={e => updateState(e.target.value)} disabled={!options.length} > <option /> {options.map(item => ( <option key={item} value={item}> {item} </option> ))} </select> </label> ); }); export default Dropdown;y usarlo como
import React, { useState, useEffect } from "react"; import useDropdown from "./useDropdown"; const SomeComponent = () => { const [animal, updateAnimal] = useState("dog"); const [breed, updateBreed] = useState(""); return ( <div className="search-params"> <form> <label htmlFor="location"> Location <input id="location" value={location} placeholder="Location" onChange={e => updateLocation(e.target.value)} /> </label> <Dropdown label="animal" value={animal} updateState={updateAnimal} options={ANIMALS}/> <Dropdown label="breed" value={breed} updateState={updateBreed} options={breeds}/> <button>Submit</button> </form> </div> ); }; export default SomeComponent;Anti-patrón es una frase tan contundente para describir soluciones simples o complejas con las que otros desarrolladores no están de acuerdo. Estoy de acuerdo con el punto de vista de Drew de que el gancho rompe el diseño convencional al hacer más de lo que debería.
Según la documentación del gancho de React , el propósito de un gancho es permitirle usar el estado y otras características de React sin escribir una clase. Por lo general, esto se considera establecer el estado, realizar tareas computacionales , realizar API u otras consultas en un asunto asíncrono y responder a la entrada del usuario. Idealmente, un componente funcional debería ser intercambiable con un componente de clase, pero en realidad, esto es mucho más difícil de lograr.
La solución particular para crear componentes desplegables, aunque funciona, no es una buena solución. ¿Por qué? Es confuso, no se explica por sí mismo y es difícil comprender lo que está sucediendo. Con ganchos, deben ser simples y realizar una sola tarea, por ejemplo, un controlador de devolución de llamada de botón, calcular y devolver un resultado memorizado, o realizar alguna otra tarea que normalmente delegaría a this.doSomething() .
Los ganchos que devuelven JSX no son realmente ganchos, son solo componentes funcionales, incluso si usan la convención de nomenclatura de prefijo correcta para los ganchos.
También hay confusión sobre React y la comunicación unidireccional para las actualizaciones de componentes. No hay restricciones sobre la forma en que pueden pasar los datos y pueden tratarse de manera similar a Angular. Hay bibliotecas como mobx que le permite suscribirse y publicar cambios en las propiedades de clase compartidas, que actualizarán cualquier componente de la interfaz de usuario que escuche, y ese componente también puede actualizarlo. También puede usar RxJS para realizar cambios asincrónicos en cualquier momento, que pueden actualizar la interfaz de usuario.
El ejemplo específico se aleja de los principios SOLID y proporciona puntos de entrada para que el componente principal controle los datos del componente secundario. Esto es típico de los lenguajes fuertemente tipados, como Java, donde es más difícil hacer una comunicación asincrónica (no es realmente un problema en estos días, pero solía serlo). No hay ninguna razón por la que un componente principal no pueda actualizar un componente secundario: es una parte fundamental de React. Cuanta más abstracción agregue, más complejidad agregará y más puntos de falla.
Agregar el uso de funciones asincrónicas, observables (mobx/rxjs) o contexto puede reducir el acoplamiento directo de datos, pero creará una solución más compleja.