ansango

Conceptos avanzados ⚛️

Autor
avatar
Name
Anibal Santos
Publicado
Lectura
4 '
Conceptos avanzados ⚛️

Error boundaries

Son componentes de React que capturan los errores en cualquier hijo del árbol de componentes. Son una especie de salvaguarda. Nos dan un log de esos errores que se producen. Nos muestran una interfaz en vez del árbol de componentes roto. Es como una especie de try catch

Podemos utilizarlos por ejemplo cuando falla una API cuando ésta nos devuelve algo inesperado, algo que no podamos controlar. Es interesante definir Error Boundaries en partes sensibles de la aplicación, en diferentes niveles, donde no podamos controlar errores inesperados.

Sólo funcionan con clases.

const NoResults = (props) => {
if (!props.results) {
throw new Error('No results prop received')
}
return props.results.length && <span>No hay resultados disponibles</span>
}
export default NoResults
<ErrorBoundary>
<NoResults />
</ErrorBoundary>
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
// usamos este método para el estado
static getDerivedStateFromError(error) {
return { hasError: true }
}
// usamos este método para logs
componentDidCatch(error, errorInfo) {
console.log(error, errorInfo)
}
render() {
if (this.state.hasError) {
return <h1>We are sorry, there was a fatal error</h1>
}
return this.props.children
}
}
export default ErrorBoundary

Un ejemplo más real, partiendo de códigos anteriores sería el siguiente:

  • Componente Bug
const BugComponent = () => {
const handleClick = () => {}
throw Error("I'm a buggy component")
return <button onClick={handleClick}>Click me! 🚀</button>
}
export default BugComponent
  • Error Boundary
export default class ErrorCatcher extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
console.log(error.toString(), errorInfo.componentStack)
}
render() {
if (this.state.hasError) {
return <p>Something went wrong.</p>
}
return this.props.children
}
}
  • App
const App = () => {
return (
<div className="App">
<ErrorCatcher>
<BugComponent />
</ErrorCatcher>
<div>{/* Componentes */}</div>
</div>
)
}
export default App

Fragments

Los fragments nos permiten agrupar una lista de componentes hijo sin tener que añadir nodos al DOM

const MyComponent = () => {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
)
}

Este códgio anterior es lo mismo que esto:

const MyComponent = () => {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
)
}

High Order Components

Son funciones que reciben un componente como parámetro y devuelven un componente modificado. No son parte real de la API de React, pero suponen un patrón a utilizar para reutilizar la lógica de un componente. Nos permiten inyectar cosas, modificar propiedades, etc... Son como una especie de wrapper.

Están en desuso, pero a continuación vemos un ejemplo:

  • High order functional component
const withRedBox = (Component) => ({ ...props }) => (
<Component style={{ border: 'red 1px solid' }} {...props} />
)
  • High order class component
const withRedBox = (Component) => {
class WithRedBox extends React.Component {
render() {
return <Component style={{ border: 'red 1px solid' }} {...this.props} />
}
}
}

Cada vez tienden a usarse menos por la aparición de los hooks.

Ejemplo más real:

  • High Order Component
import React from 'react'
const withRedBox = (Component) => ({ ...props }) => (
<Component style={{ border: 'red 1px solid' }} {...props} />
)
export default withRedBox
import withRedBox from '../utils/withRedBox'
const mockApiCall = async (isFemale) =>
new Promise((resolve) => {
setTimeout(() => {
resolve(isFemale ? 'Michelle Jordan' : 'Michael Jordan')
}, 5000)
})
const Header = ({ title, onClick, isFemale = false, style = {} }) => {
const [userName, setUserName] = React.useState('Anibal')
React.useEffect(() => {
const fetchUserName = async () => {
const name = await mockApiCall(isFemale)
setUserName(name)
}
fetchUserName()
}, [isFemale])
return (
<header style={style} onClick={onClick}>
<h1>{title}</h1>
<nav>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
<li>Option 4</li>
</ul>
</nav>
<h3>{userName}</h3>
</header>
)
}
export default withRedBox(Header)
  • App
import Header from './components/Header'
import { useState } from 'react'
const App = () => {
const [isFemale, setIsFemale] = useState(false)
const title = 'React Training'
const handleHeaderClick = () => setIsFemale(!isFemale)
return (
<div className="App">
<Header title={title} isFemale={isFemale} onClick={handleHeaderClick} />
<div>{/* Componentes */}</div>
</div>
)
}
export default App

❤️ Espero que te haya gustado la entrada.

Puedes continuar leyendo el siguiente capítulo sobre Context API, volver al capítulo anterior de Hooks, o volver al Índice.

Utilizo cookies para mejorar mi contenido. Al continuar utilizando este sitio, estás aceptando el uso que hago de las cookies.