Si ha estado en el ecosistema React por un tiempo, existe la posibilidad de que haya oído hablar Componentes de orden superior. Veamos una implementación simple mientras intentamos explicar la idea central. A partir de aquí deberías hacerte una buena idea de cómo funcionan e incluso ponerlos en práctica.
¿Por qué componentes de orden superior?
A medida que cree aplicaciones React, se encontrará con situaciones en las que desee compartir la misma funcionalidad en varios componentes.
Por ejemplo: necesita administrar el estado de los usuarios actualmente conectados en su aplicación. En lugar de administrar ese estado en todos los componentes que necesitan ese estado, puede crear un componente de orden superior para separar el estado del usuario registrado en un componente contenedor y luego pasar ese estado a los componentes que lo utilizarán.
Los componentes que reciben el estado del componente de orden superior funcionarán como componentes de presentación. Se les pasa el estado y condicionalmente renderizan la interfaz de usuario en función de él. No se preocupan por la gestión del estado.
Veamos otro ejemplo. Supongamos que tiene tres archivos JSON en su aplicación. Estos archivos contienen diferentes datos que se cargarán en su aplicación en tres componentes diferentes. Quiere darles a sus usuarios la posibilidad de buscar los datos cargados desde estos archivos. Podría implementar una función de búsqueda en los tres componentes. Es posible que esta duplicación no sea un problema al principio, pero a medida que su aplicación crezca y más componentes necesiten esta funcionalidad, la duplicación constante será engorrosa y propensa a problemas.
Una mejor manera de avanzar es crear un componente de orden superior para manejar la funcionalidad de búsqueda. Con él, puede envolver los otros componentes individualmente en su componente de orden superior.
¿Cómo funcionan los componentes de orden superior?
Los documentos de React dicen que los componentes de orden superior tomar un componente y devolver un componente.
El uso de componentes de orden superior resulta útil cuando está preparado desde el punto de vista arquitectónico para separar los componentes del contenedor de los componentes de la presentación. El componente de presentación es a menudo un componente funcional sin estado que toma accesorios y representa la interfaz de usuario. Los componentes funcionales sin estado son funciones simples de JavaScript que no tienen estados. He aquí un ejemplo:
import React from 'react'
const App = ({name}) => {
return (
<div>
<h2>This is a functional component. Your name is {name}.</h2>
</div>
)
}
ReactDOM.render(<App name="Kingsley" />, document.getElementById("root"));
El componente contenedor hace el trabajo de administrar el estado. El contenedor, en este caso, es el componente de orden superior.
En el ejemplo de búsqueda del que hablamos anteriormente, el componente de búsqueda sería el componente contenedor que administra el estado de búsqueda y envuelve los componentes de presentación que necesitan la funcionalidad de búsqueda. De lo contrario, los componentes de la presentación no tienen idea del estado o de cómo se gestiona.
Un ejemplo de componente de orden superior
Comencemos con un ejemplo básico. Aquí hay un componente de orden superior que transforma y devuelve nombres de usuario en mayúsculas:
const hoc = (WrappedComponent) => (props) => {
return (
<div>
<WrappedComponent {...props}>
{props.children.toUpperCase()}
</WrappedComponent>
</div>
)
}
Este componente de orden superior recibe un WrappedComponent
como argumento. Luego devuelve un nuevo componente con los accesorios que se le pasan creando un elemento React. Nosotros llamamos .toUpperCase()
sobre el props.children
, para transformar lo pasado props.children
a mayúsculas.
Para hacer uso de este componente de orden superior, necesitamos crear un componente que reciba accesorios y represente a los hijos.
const Username = (props) => (
<div>{props.children}</div>
)
A continuación, envolvemos Username
con el componente de orden superior. Guardemos eso en una variable:
const UpperCaseUsername = hoc(Username)
En nuestro App
componente, ahora podemos usarlo así:
const App = () => (
<div>
<UpperCaseUsername>Kingsley</UpperCaseUsername>
</div>
);
El UpperCaseUsername
componente es simplemente una representación del Username
UI que, a su vez, extrae el estado de la WrappedComponent
actuando como el componente de orden superior.
Un componente de orden superior más práctico
Imagina que queremos crear una lista de ubicaciones con un formulario de búsqueda que las filtre. El JSON estará en archivos planos y se cargará como componentes separados. Comencemos cargando los datos.
Nuestro primer componente cargará ubicaciones para nuestros usuarios. Haremos uso de .map()
para recorrer los datos contenidos en ese archivo JSON.
import React from 'react'
// Where the data is located
import preload from './locations.json'
// Manages the data
import LocationCard from './LocationCard'
// Renders the presentation of the data
const Location = (props) => {
return (
<div>
<div>
<div>
<h2>Preferred Locations</h2>
</div>
</div>
<div>
{preload.data
.map(location => <LocationCard key={location.id} {...location} />)}
</div>
</div>
)
}
export default Location
Este componente representará los datos en un LocationCard
componente. Lo moví a un componente diferente para dejar las cosas claras. Este componente es un componente funcional que maneja la presentación de nuestros datos. Los datos (ubicación) del archivo se reciben a través de props
, y cada ubicación se transmitirá a la LocationCard
componente.
Ahora necesitamos un segundo componente que, eventualmente, también necesitará funcionalidad de búsqueda. Será muy similar al primer componente que acabamos de construir, pero tendrá un nombre diferente y cargará datos desde un lugar diferente.
Queremos que nuestros usuarios puedan buscar elementos utilizando un input
campo. La lista de elementos que se muestran en la aplicación debe estar determinada por el estado de la búsqueda. Esta funcionalidad se compartirá entre los dos componentes en los que estamos trabajando. Gracias a la idea de componentes de orden superior, podemos crear un componente contenedor de búsqueda y envolverlo con otros componentes.
Llamemos al componente withSearch
. Este componente renderizará el input
campo para nuestra búsqueda y también gestionar nuestra searchTerm
Expresar. El searchTerm
se pasará como accesorios al componente envuelto, que se utilizará para filtrar los datos extraídos:
import React, { Component } from 'react'
const withSearch = (WrappedComponent) => {
return class extends Component {
state = {
searchTerm: ''
}
handleSearch = event => {
this.setState({ searchTerm: event.target.value })
}
render() {
return (
<div>
<div>
<input onChange={this.handleSearch} value={this.state.searchTerm} type="text" placeholder="Search" />
</div>
<WrappedComponent searchTerm={this.state.searchTerm} />
</div>
)
}
}
}
export default withSearch
El searchTerm
se le da un estado de una cadena vacía. El valor ingresado por el usuario en el cuadro de búsqueda se obtiene y se utiliza para establecer el nuevo estado para searchTerm
. A continuación, pasamos searchTerm
al WrappedComponent
. Haremos uso de esto cuando filtremos los datos.
Para hacer uso del componente de orden superior, necesitamos realizar algunos cambios en nuestro componente de presentación.
import React, { Component } from 'react'
// Where the data is located
import preload from './locations.json'
// Searches the data
import withSearch from './withSearch
// Manages the data
import LocationCard from './LocationCard'
// Renders the presentation of the data
const Location = (props) => {
const { searchTerm } = props
return (
<div>
<div>
<div>
<h2>Preferred Locations</h2>
</div>
</div>
<div>
{preload.data
// Filter locations by the inputted search term
.filter(location => `${location.name} ${location.zone} ${location.region}`.toUpperCase().indexOf(searchTerm.toUpperCase()) >= 0)
// Loop through the locations
.map(location => <LocationCard key={location.id} {...location} />)}
</div>
</div>
)
}
export default withSearch(Location)
Lo primero que hicimos anteriormente fue importar el componente de orden superior. Luego agregamos un método de filtro para filtrar los datos en función de lo que ingresa el usuario en la entrada de búsqueda. Por último, tenemos que envolverlo con el withSearch
componente.
Consulte el Pen hoc Pen de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Conclusión
Los componentes de orden superior no tienen por qué dar miedo. Después de comprender los conceptos básicos, puede poner en práctica el concepto abstrayendo las funcionalidades que se pueden compartir entre los diferentes componentes.
Más recursos
- Componentes de orden superior: documentación de React
- Reaccionar componentes de orden superior en profundidad – por Fran Guijarro
- Componentes de orden superior en React – por Chris Nwamba
- Más ejemplos: colección CodePen