Component
es la clase base para los componentes de React definidos como clases en JavaScript. Los componentes de clase aún son compatibles con React, pero no recomendamos usarlos en nuevo código.
class Greeting extends Component {
render() {
return <h1>Hola, {this.props.name}!</h1>;
}
}
- Referencia
Component
context
props
refs
state
constructor(props)
componentDidCatch(error, info)
componentDidMount()
componentDidUpdate(prevProps, prevState, snapshot?)
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
forceUpdate(callback?)
getChildContext()
getSnapshotBeforeUpdate(prevProps, prevState)
render()
setState(nextState, callback?)
shouldComponentUpdate(nextProps, nextState, nextContext)
UNSAFE_componentWillMount()
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
UNSAFE_componentWillUpdate(nextProps, nextState)
static childContextTypes
static contextTypes
static contextType
static defaultProps
static getDerivedStateFromError(error)
static getDerivedStateFromProps(props, state)
- Uso
- Alternativas
Referencia
Component
Para definir un componente de React como clase, se debe extender la clase incorporada Component
y definir un método render
.
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hola, {this.props.name}!</h1>;
}
}
Sólo el método render
es obligatorio, los demás son opcionales.
context
El contexto de un componente de clase está disponible como this.context
. Solo está disponible si especificas cual contexto deseas recibir usando static contextType (moderno) o static contextTypes
(deprecado).
Un componente de clase solo puede leer un contexto a la vez.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}
props
Las props que se pasan a un componente de clase están disponibles como this.props
.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
<Greeting name="Taylor" />
refs
Te permite acceder a legacy string refs para este componente.
state
El estado de un componente de clase está disponible como this.state
. El campo state
debe ser un objeto. No mutes el estado directamente. Si deseas cambiar el estado, llama a setState
con el nuevo estado.
class Counter extends Component {
state = {
age: 42,
};
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};
render() {
return (
<>
<button onClick={this.handleAgeChange}>
Incrementar edad
</button>
<p>Tienes {this.state.age} años.</p>
</>
);
}
}
constructor(props)
El constructor se ejecuta antes de que el componente de clase se monte (se agregue a la pantalla). Normalmente, en React se utiliza el constructor únicamente para dos propósitos. Te permite declarar el estado y enlazar los métodos de la clase con la instancia de la clase:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// ...
}
Si usas la sintaxis moderna de JavaScript, rara vez se necesitan constructores. En su lugar, puedes reescribir este código usando la sintaxis de campo de clase pública que es compatible tanto con navegadores modernos como con herramientas como Babel:
class Counter extends Component {
state = { counter: 0 };
handleClick = () => {
// ...
}
Un constructor no debería tener efectos secundarios ni suscripciones.
Parámetros
props
: Las props iniciales del componente.
Retorna
El constructor
no debe retornar nada.
Precauciones
-
No ejecutes ningún efecto secundario o suscripciones en el constructor. En su lugar, utiliza
componentDidMount
para eso. -
Dentro de un constructor, debes llamar a
super(props)
antes que cualquier otra declaración. Si no lo haces,this.props
seráundefined
mientras se ejecuta el constructor, lo que puede ser confuso y causar errores. -
El constructor es el único lugar donde puedes asignar
this.state
directamente. En todos los demás métodos, debes utilizarthis.setState()
en su lugar. No llames asetState
en el constructor. -
Cuando usas renderizado en el servidor, el constructor también se ejecutará en el servidor, seguido del método
render
. Sin embargo, los métodos del ciclo de vida comocomponentDidMount
ocomponentWillUnmount
no se ejecutarán en el servidor. -
Cuando Strict Mode está activado, React llamará al constructor dos veces en desarrollo y luego descartará una de las instancias. Esto ayuda a notar los efectos secundarios accidentales que deben moverse fuera del
constructor
.
componentDidCatch(error, info)
Si defines componentDidCatch
, React lo llamará cuando algún componente hijo (incluso los distantes) lance un error durante el renderizado. Esto te permite registrar ese error en un servicio de reporte de errores en producción.
Normalmente, se utiliza junto con static getDerivedStateFromError
, lo que te permite actualizar el estado en respuesta a un error y mostrar un mensaje de error al usuario. Un componente con estos métodos se llama error boundary.
Parámetros
-
error
: El error que fue lanzado. En la práctica, generalmente será una instancia deError
, pero no se garantiza ya que JavaScript permitelanzar
cualquier valor, incluyendo cadenas de texto o inclusonull
. -
info
: Un objeto que contiene información adicional sobre el error. Su campocomponentStack
contiene una pila de rastreo con el componente que lanzó el error, así como los nombres y ubicaciones de origen de todos sus componentes padres. En producción, los nombres de los componentes se reducirán. Si configuras la notificación de errores en producción, puedes decodificar la pila de componentes utilizando sourcemaps de la misma manera que lo harías con las pilas de errores regulares de JavaScript.
Retorna
componentDidCatch
no debería retornar nada.
Precauciones
-
En el pasado, era común llamar a
setState
dentro decomponentDidCatch
para actualizar la interfaz de usuario y mostrar un mensaje de error alternativo. Esto está obsoleto a favor de definirstatic getDerivedStateFromError
. -
Las versiones de producción y desarrollo de React difieren ligeramente en la forma en que
componentDidCatch
maneja los errores. En desarrollo, los errores se propagarán awindow
, lo que significa que cualquierwindow.onerror
owindow.addEventListener('error', callback)
interceptará los errores capturados porcomponentDidCatch
. En producción, en cambio, los errores no se propagarán, lo que significa que cualquier administrador de errores principal solo recibirá errores no capturados explícitamente por `componentDidCatch.
componentDidMount()
Si defines el método componentDidMount
, React lo llamará cuando tu componente se agregue por primera vez (se monte) en la pantalla. Este es un lugar común para comenzar la obtención de datos, configurar suscripciones o manipular los nodos del DOM.
Si implementas componentDidMount
, generalmente debes implementar otros métodos del ciclo de vida para evitar errores. Por ejemplo, si componentDidMount
lee algún estado o propiedades, también debes implementar componentDidUpdate
para manejar sus cambios, y componentWillUnmount
para limpiar lo que componentDidMount
estaba haciendo.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
Parámetros
componentDidMount
no toma ningún parámetro.
Retorna
componentDidMount
no debería devolver nada.
Precauciones
-
Cuando se activa el modo estricto, en desarrollo React llamará a
componentDidMount
, luego inmediatamente llamará acomponentWillUnmount
y luego llamará acomponentDidMount
nuevamente. Esto te ayuda a notar si olvidaste implementarcomponentWillUnmount
o si su lógica no refleja completamente lo que hacecomponentDidMount
. -
Aunque puedes llamar a
setState
inmediatamente encomponentDidMount
, es mejor evitarlo siempre que puedas. Esto provocará un renderizado adicional, pero sucederá antes de que el navegador actualice la pantalla. Esto garantiza que aunquerender
se llame dos veces en este caso, el usuario no verá el estado intermedio. Usa este patrón con precaución porque a menudo causa problemas de rendimiento. En la mayoría de los casos, deberías ser capaz de asignar el estado inicial en elconstructor
en su lugar. Sin embargo, puede ser necesario en casos como modales y tooltips cuando necesitas medir un nodo DOM antes de renderizar algo que depende de su tamaño o posición.
componentDidUpdate(prevProps, prevState, snapshot?)
Si defines el método componentDidUpdate
, React lo llamará inmediatamente después de que tu componente haya sido renderizado de nuevo con las props o el estado actualizado. Este método no se llama para el renderizado inicial.
Puedes utilizarlo para manipular el DOM después de una actualización. También es un lugar común para hacer solicitudes de red siempre y cuando compares las props actuales con las props anteriores (por ejemplo, una solicitud de red puede no ser necesaria si las props no han cambiado). Normalmente, lo usarías junto con componentDidMount
y componentWillUnmount
:
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
Parámetros
-
prevProps
: Las props antes de la actualización. ComparaprevProps
conthis.props
para determinar lo que cambió. -
prevState
: El estado antes de la actualización. ComparaprevState
conthis.state
para determinar lo que cambió. -
snapshot
: Si implementastegetSnapshotBeforeUpdate
,snapshot
contendrá el valor que retornaste desde ese método. De lo contrario, seráundefined
.
Retorna
componentDidUpdate
no debería devolver nada.
Precauciones
-
componentDidUpdate
no será llamado sishouldComponentUpdate
está definido y devuelvefalse
. -
La lógica dentro de
componentDidUpdate
generalmente debería estar envuelta en condiciones que comparanthis.props
conprevProps
ythis.state
conprevState
. De lo contrario, existe el riesgo de crear bucles infinitos. -
Aunque puedes llamar
setState
inmediatamente encomponentDidUpdate
, es mejor evitarlo siempre que puedas. Desencadenará una representación adicional, pero sucederá antes de que el navegador actualice la pantalla. Esto garantiza que aunquerender
se llamará dos veces en este caso, el usuario no verá el estado intermedio. Este patrón a menudo causa problemas de rendimiento, pero puede ser necesario para casos raros como modales y tooltips cuando necesita medir un nodo DOM antes de renderizar algo que depende de su tamaño o posición.
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
Si defines el método componentWillUnmount
, React lo llamará antes de que tu componente sea eliminado (desmontado) de la pantalla. Este es un lugar común para cancelar la obtención de datos o eliminar suscripciones.
La lógica dentro de componentWillUnmount
debe «reflejar» la lógica dentro de componentDidMount
. Por ejemplo, si componentDidMount
configura una suscripción, componentWillUnmount
debe limpiar esa suscripción. Si la lógica de limpieza en componentWillUnmount
lee algunas props o estado, generalmente también deberás implementar componentDidUpdate
para limpiar recursos (como suscripciones) correspondientes a las props y estados antiguos.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
Parámetros
componentWillUnmount
no recibe ningún parámetro.
Retorna
componentWillUnmount
no debería devolver nada.
Precauciones
- Cuando el Modo Estricto está activado, en desarrollo React llamará a
componentDidMount
y luego llamará inmediatamente acomponentWillUnmount
, y luego llamará acomponentDidMount
de nuevo. Esto ayuda a notar si olvidaste implementarcomponentWillUnmount
o si su lógica no refleja completamente lo que hacecomponentDidMount
.
forceUpdate(callback?)
forceUpdate
fuerza a un componente a volver a renderizarse.
Por lo general, esto no es necesario. Si el método render
de tu componente solo lee de this.props
, this.state
o this.context
, se volverá a renderizar automáticamente cuando llames a setState
dentro de tu componente o uno de sus padres. Sin embargo, si el método render
de tu componente lee directamente de una fuente de datos externa, debes indicarle a React que actualice la interfaz de usuario cuando cambie esa fuente de datos. Para eso sirve forceUpdate
.
Trata de evitar todas las situaciones donde se necesita utilizar forceUpdate
y solo lee de this.props
y this.state
en render
.
Parámetros
- opcional
callback
Si se especifica, React llamará alcallback
que hayas proporcionado después de que se haya realizado la actualización.
Retorna
forceUpdate
no devuelve nada.
Precauciones
- Si llamas a
forceUpdate
, React volverá a renderizar sin llamar ashouldComponentUpdate
.
getChildContext()
Permite especificar los valores para el contexto heredado que es proporcionado por este componente.
getSnapshotBeforeUpdate(prevProps, prevState)
Si implementas getSnapshotBeforeUpdate
, React lo llamará inmediatamente antes de actualizar el DOM. Esto permite que tu componente capture cierta información del DOM (por ejemplo, la posición de desplazamiento) antes de que potencialmente cambie. Cualquier valor devuelto por este método de ciclo de vida se pasará como parámetro a componentDidUpdate
.
Por ejemplo, puedes usarlo en una interfaz de usuario como un hilo de chat que necesita conservar su posición de desplazamiento durante las actualizaciones:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
En el ejemplo anterior, es importante leer la propiedad scrollHeight
directamente en getSnapshotBeforeUpdate
. No es seguro leerla en render
, UNSAFE_componentWillReceiveProps
o UNSAFE_componentWillUpdate
porque existe un posible lapso de tiempo entre la llamada a estos métodos y la actualización del DOM por parte de React.
Parámetros
-
prevProps
: Props antes de la actualización. ComparaprevProps
conthis.props
para determinar lo que cambió. -
prevState
: Estado antes de la actualización. ComparaprevState
conthis.state
para determinar lo que cambió.
Retorna
Deberías devolver un valor de instantánea de cualquier tipo que desees o null
. El valor que devuelvas se pasará como tercer argumento a componentDidUpdate
.
Precauciones
getSnapshotBeforeUpdate
no se llamará si se define shouldComponentUpdate
y devuelve false
.
render()
El método render
es el único método requerido en un componente de clase.
El método render
debería especificar lo que deseas que aparezca en la pantalla, por ejemplo:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
React puede llamar a render
en cualquier momento, por lo que no debes asumir que se ejecuta en un momento determinado. Por lo general, el método render
debería devolver una pieza de JSX, pero se admiten algunos otros tipos de retorno (como cadenas). Para calcular el JSX devuelto, el método render
puede leer this.props
, this.state
y this.context
.
Deberías escribir el método render
como una función pura, lo que significa que debería devolver el mismo resultado si las props, el estado y el contexto son iguales. Tampoco debería contener efectos secundarios (como configurar suscripciones) o interactuar con las APIs del navegador. Los efectos secundarios deberían ocurrir en controladores de eventos o en métodos como componentDidMount
.
Parámetros
-
prevProps
: Props anteriores a la actualización. ComparaprevProps
conthis.props
para determinar qué cambió. -
prevState
: Estado anterior a la actualización. ComparaprevState
conthis.state
para determinar qué cambió.
Retorna
render
puede devolver cualquier nodo React válido. Esto incluye elementos React como <div />
, cadenas de texto, números, portales, nodos vacíos (null
, undefined
, true
y false
), y arrays de nodos de React.
Precauciones
render
debe ser escrito como una función pura de props, state, y context. No debe tener efectos secundarios.render
no será llamado sishouldComponentUpdate
está definido y devuelvefalse
.- Cuando Strict Mode está activado, React llamará a
render
dos veces en desarrollo y luego descartará uno de los resultados. Esto te ayuda a notar los efectos secundarios accidentales que necesitan ser movidos fuera del métodorender
. - No hay una correspondencia uno a uno entre la llamada a
render
y la posterior llamada acomponentDidMount
ocomponentDidUpdate
. Algunos de los resultados de la llamada arender
pueden ser descartados por React cuando es beneficioso.
setState(nextState, callback?)
Llama a setState
para actualizar el estado de tu componente React.
class Form extends Component {
state = {
name: 'Taylor',
};
handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}
render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.
</>
);
}
}
setState
encola cambios en el estado del componente. Le dice a React que este componente y sus hijos necesitan volver a renderizarse con el nuevo estado. Esta es la forma principal en la que actualizará la interfaz de usuario en respuesta a interacciones.
También puedes pasar una función a setState
. Esto te permite actualizar el estado basándote en el estado anterior:
handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}
No es necesario hacer esto, pero es útil si desea actualizar el estado varias veces durante el mismo evento.
Parámetros
-
nextState
: Puede ser un objeto o una función.- Si pasa un objeto como
nextState
, se fusionará superficialmente enthis.state
. - Si pasa una función como
nextState
, se tratará como una función de actualización. Debe ser pura, debe tomar como argumentos el estado pendiente y las props, y debe devolver el objeto que se fusionará superficialmente enthis.state
. React pondrá su función de actualización en una cola y volverá a renderizar su componente. Durante el próximo renderizado, React calculará el siguiente estado aplicando todas las actualizaciones en cola al estado anterior.
- Si pasa un objeto como
-
opcional
callback
: Si se especifica, React llamará alcallback
que ha proporcionado después de que se haya confirmado la actualización.
Retorna
setState
no devuelve nada.
Precauciones
-
Piensa en
setState
como una solicitud en lugar de un comando inmediato para actualizar el componente. Cuando varios componentes actualizan su estado en respuesta a un evento, React los agrupa y los renderiza juntos en una sola pasada al final del evento. En el caso raro de que necesites forzar que una actualización de estado en particular se aplique de forma sincrónica, puedes envolverla enflushSync
, pero esto puede afectar el rendimiento. -
setState
no actualizathis.state
inmediatamente. Esto puede ser un problema potencial si se leethis.state
justo después de llamar asetState
. En su lugar, utilizacomponentDidUpdate
o el argumento decallback
de setState, ya que ambos están garantizados para activarse después de que se haya aplicado la actualización. Si necesitas establecer el estado basado en el estado anterior, puedes pasar una función anextState
como se describe anteriormente.
shouldComponentUpdate(nextProps, nextState, nextContext)
Si defines shouldComponentUpdate
, React lo llamará para determinar si se puede omitir una nueva representación.
Si estás seguro de que quieres escribirlo a mano, puedes comparar this.props
con nextProps
y this.state
con nextState
y devolver false
para indicar a React que se puede omitir la actualización.
class Rectangle extends Component {
state = {
isHovered: false
};
shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nothing has changed, so a re-render is unnecessary
return false;
}
return true;
}
// ...
}
React llama a shouldComponentUpdate
antes de renderizar cuando se reciben nuevas props o estado. Por defecto, devuelve true
. Este método no se llama para la renderización inicial o cuando se usa forceUpdate
.
Parámetros
nextProps
: Las próximas props que el componente está a punto de renderizar. ComparenextProps
conthis.props
para determinar lo que cambió.nextState
: El próximo estado con el que el componente está a punto de renderizar. ComparenextState
conthis.state
para determinar lo que cambió.nextContext
: El próximo contexto con el que el componente está a punto de renderizar. ComparenextContext
conthis.context
para determinar lo que cambió. Solo está disponible si se especificastatic contextType
(moderno) ostatic contextTypes
(legado).
Retorna
Devuelve true
si quieres que el componente se vuelva a renderizar. Ese es el comportamiento predeterminado.
Devuelve false
para indicar a React que se puede omitir la re-renderización.
Precauciones
-
Este método solo existe como una optimización de rendimiento. Si su componente falla sin él, primero solucione eso.
-
Considera usar
PureComponent
en lugar de escribirshouldComponentUpdate
manualmente.PureComponent
compara superficialmente las props y el estado, y reduce la posibilidad de que omita una actualización necesaria. -
No recomendamos hacer verificaciones de igualdad profunda o usar
JSON.stringify
enshouldComponentUpdate
. Esto hace que el rendimiento sea impredecible y dependa de la estructura de datos de cada prop y estado. En el mejor de los casos, corre el riesgo de introducir paradas de varios segundos en su aplicación, y en el peor de los casos, corre el riesgo de que se bloquee. -
Devolver
false
no impide que los componentes secundarios se vuelvan a renderizar cuando cambia su estado. -
Devolver
false
no garantiza que el componente no se volverá a renderizar. React utilizará el valor de retorno como una sugerencia, pero aún puede elegir volver a renderizar el componente si tiene sentido hacerlo por otras razones.
UNSAFE_componentWillMount()
Si defines UNSAFE_componentWillMount
, React lo llamará inmediatamente después del constructor
. Solo existe por razones históricas y no debe usarse en ningún código nuevo. En su lugar, usa una de las alternativas:
- Para inicializar el estado, declara
state
como un campo de clase o establecethis.state
dentro delconstructor
. - Si necesitas ejecutar un efecto secundario o configurar una suscripción, mueve esa lógica a
componentDidMount
en su lugar.
Ver ejemplos de migración de los ciclos de vida inseguros.
Parámetros
UNSAFE_componentWillMount
no acepta ningún parámetro.
Retorna
UNSAFE_componentWillMount
no debería retornar nada.
Precauciones
-
UNSAFE_componentWillMount
no se llamará si el componente implementastatic getDerivedStateFromProps
ogetSnapshotBeforeUpdate
. -
A pesar de su nombre,
UNSAFE_componentWillMount
no garantiza que el componente se montará si su aplicación usa características modernas de React comoSuspense
. Si se suspende un intento de renderizado (por ejemplo, porque el código de algún componente hijo aún no se ha cargado), React descartará el árbol en progreso y tratará de construir el componente desde cero durante el próximo intento. Por eso, este método es «inseguro». El código que depende del montaje (como agregar una suscripción) debe ir encomponentDidMount
. -
UNSAFE_componentWillMount
es el único método del ciclo de vida que se ejecuta durante renderizado en el servidor. Para todos los propósitos prácticos, es idéntico alconstructor
, por lo que debería usar elconstructor
para este tipo de lógica en su lugar.
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
Si defines UNSAFE_componentWillReceiveProps
, React lo llamará cuando el componente reciba nuevas props. Solo existe por razones históricas y no se debe usar en ningún código nuevo. En su lugar, utiliza una de las siguientes alternativas:
- Si necesitas realizar un efecto secundario (por ejemplo, buscar datos, ejecutar una animación o volver a inicializar una suscripción) en respuesta a cambios en las props, mueve esa lógica a
componentDidUpdate
en su lugar. - Si necesitas evitar volver a calcular algunos datos solo cuando cambia una prop, utiliza un ayudante de memoización en su lugar.
- Si necesitas «restablecer» algunos estados cuando cambia una prop, considera hacer que un componente sea totalmente controlado o totalmente no controlado con una clave en su lugar.
- Si necesitas «ajustar» algunos estados cuando cambia una prop, comprueba si puedes calcular toda la información necesaria solo a partir de las props durante la renderización. Si no puedes, utiliza
static getDerivedStateFromProps
en su lugar.
Ver ejemplos de migración de ciclos de vida inseguros.
Parámetros
nextProps
: Las próximas props que el componente está a punto de recibir de su componente padre. ComparanextProps
conthis.props
para determinar qué ha cambiado.nextContext
: El próximo contexto que el componente está a punto de recibir del proveedor más cercano. ComparanextContext
conthis.context
para determinar qué ha cambiado. Solo está disponible si se especificastatic contextType
(moderno) ostatic contextTypes
(legado).
Retorna
UNSAFE_componentWillReceiveProps
no debe devolver nada.
Precauciones
-
UNSAFE_componentWillReceiveProps
no se llamará si el componente implementastatic getDerivedStateFromProps
ogetSnapshotBeforeUpdate
. -
A pesar de su nombre,
UNSAFE_componentWillReceiveProps
no garantiza que el componente recibirá esas props si tu aplicación utiliza características modernas de React comoSuspense
. Si un intento de renderizado se suspende (por ejemplo, porque el código para algún componente hijo aún no se ha cargado), React descarta el árbol en progreso e intenta construir el componente desde cero durante el próximo intento. Para el momento del próximo intento de renderizado, las props podrían ser diferentes. Es por eso que este método es «inseguro». El código que debe ejecutarse solo para actualizaciones confirmadas (como restablecer una suscripción) debe ir encomponentDidUpdate
. -
UNSAFE_componentWillReceiveProps
no significa que el componente haya recibido props diferentes a las de la última vez. Debes compararnextProps
ythis.props
por ti mismo para verificar si algo ha cambiado. -
React no llama a
UNSAFE_componentWillReceiveProps
con props iniciales durante el montaje. Solo llama a este método si alguna de las props del componente se va a actualizar. Por ejemplo, llamar asetState
generalmente no activaUNSAFE_componentWillReceiveProps
dentro del mismo componente.
UNSAFE_componentWillUpdate(nextProps, nextState)
Si defines UNSAFE_componentWillUpdate
, React lo llamará antes de renderizar con las nuevas props o estado. Solo existe por razones históricas y no debe usarse en ningún código nuevo. En su lugar, usa una de las alternativas siguientes:
- Si necesitas realizar un efecto secundario (por ejemplo, recuperar datos, ejecutar una animación o reinicializar una suscripción) en respuesta a cambios de prop o estado, mueve esa lógica a
componentDidUpdate
en su lugar. - Si necesitas leer alguna información del DOM (por ejemplo, para guardar la posición actual de desplazamiento) para usarla en
componentDidUpdate
más tarde, léela dentro degetSnapshotBeforeUpdate
en su lugar.
Ver ejemplos de migración de ciclos de vida inseguros.
Parámetros
nextProps
: Las próximas props con las que el componente está a punto de renderizarse. ComparanextProps
conthis.props
para determinar qué ha cambiado.nextState
: El próximo estado con el que el componente está a punto de renderizarse. ComparanextState
conthis.state
para determinar qué ha cambiado.
Retorna
UNSAFE_componentWillUpdate
no debería devolver nada.
Precauciones
-
UNSAFE_componentWillUpdate
no se llamará sishouldComponentUpdate
está definido y devuelvefalse
. -
UNSAFE_componentWillUpdate
no se llamará si el componente implementastatic getDerivedStateFromProps
ogetSnapshotBeforeUpdate
. -
No es compatible llamar a
setState
(o cualquier método que lleve a que se llame asetState
, como despachar una acción de Redux) durantecomponentWillUpdate
. -
A pesar de su nombre,
UNSAFE_componentWillUpdate
no garantiza que el componente se actualizará si su aplicación utiliza características modernas de React comoSuspense
. Si se suspende un intento de renderizado (por ejemplo, porque el código para algún componente hijo aún no se ha cargado), React descarta el árbol en progreso e intenta construir el componente desde cero durante el próximo intento. Para el momento del próximo intento de renderizado, las props y el estado pueden ser diferentes. Es por eso que este método es «peligroso». El código que solo debe ejecutarse para actualizaciones comprometidas (como restablecer una suscripción) debe ir encomponentDidUpdate
. -
UNSAFE_componentWillUpdate
no significa que el componente haya recibido props o estado diferentes que la última vez. Necesitas compararnextProps
conthis.props
ynextState
conthis.state
por ti mismo para verificar si algo ha cambiado. -
React no llama a
UNSAFE_componentWillUpdate
con las props y el estado iniciales durante el montaje.
static childContextTypes
Te permite especificar qué contexto legado es proporcionado por este componente.
static contextTypes
Te permite especificar qué contexto heredado es consumido por este componente.
static contextType
Si deseas leer this.context
desde tu componente de clase, debes especificar qué contexto debe leer. El contexto que especifiques como static contextType
debe ser un valor creado previamente por createContext
.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}
static defaultProps
Puedes definir static defaultProps
para establecer las props predeterminadas para la clase. Se utilizarán para props undefined
y faltantes, pero no para props null
.
Por ejemplo, así es como defines que la prop color
debe tener como valor predeterminado 'blue'
:
class Button extends Component {
static defaultProps = {
color: 'blue'
};
render() {
return <button className={this.props.color}>click me</button>;
}
}
Si la propiedad color
no se proporciona o es undefined
, se establecerá por defecto en 'blue'
:
<>
{/* this.props.color is "blue" */}
<Button />
{/* this.props.color is "blue" */}
<Button color={undefined} />
{/* this.props.color is null */}
<Button color={null} />
{/* this.props.color is "red" */}
<Button color="red" />
</>
static getDerivedStateFromError(error)
Si defines static getDerivedStateFromError
, React lo llamará cuando un componente hijo (incluyendo componentes hijos distantes) arroje un error durante el rendering. Esto te permite mostrar un mensaje de error en lugar de limpiar la interfaz de usuario.
Por lo general, se utiliza junto con componentDidCatch
, que te permite enviar el informe de errores a algún servicio de análisis. Un componente con estos métodos se llama una línea de error.
Parámetros
error
: El error que se produjo. En la práctica, generalmente será una instancia deError
, pero esto no está garantizado porque JavaScript permite arrojar cualquier valor, incluyendo cadenas o inclusonull
.
Retorna
static getDerivedStateFromError
debería devolver el estado que indica al componente que muestre el mensaje de error.
Precauciones
static getDerivedStateFromError
debe ser una función pura. Si deseas realizar un efecto secundario (por ejemplo, llamar a un servicio de análisis), también debes implementarcomponentDidCatch
.
static getDerivedStateFromProps(props, state)
Si defines static getDerivedStateFromProps
, React lo llamará justo antes de llamar a render
, tanto en el montaje inicial como en actualizaciones posteriores. Debería devolver un objeto para actualizar el estado, o null
para no actualizar nada.
Este método existe para casos de uso raros donde el estado depende de los cambios en las propiedades con el tiempo. Por ejemplo, este componente Form
restablece el estado email
cuando cambia la propiedad userID
:
class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
// Any time the current user changes,
// Reset any parts of state that are tied to that user.
// In this simple example, that's just the email.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}
Ten en cuenta que este patrón requiere que mantengas un valor anterior de la propiedad (como userID
) en el estado (como prevUserID
).
Parámetros
props
: Las próximas props que el componente está a punto de renderizar.state
: El próximo estado que el componente está a punto de renderizar.
Retorna
static getDerivedStateFromProps
devuelve un objeto para actualizar el estado, o null
para no actualizar nada.
Precauciones
- Este método se ejecuta en cada renderización, independientemente de la causa. Esto es diferente de
UNSAFE_componentWillReceiveProps
, que solo se ejecuta cuando el padre causa una re-renderización y no como resultado de unsetState
local. - Este método no tiene acceso a la instancia del componente. Si lo desea, puede reutilizar algún código entre
static getDerivedStateFromProps
y otros métodos de clase extrayendo funciones puras de las props y el estado del componente fuera de la definición de la clase.
Uso
Definiendo un componente de clase
Para definir un componente React como una clase, extiende la clase integrada Component
y define un método render:
.
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
React llamará a tu método render
cada vez que necesite determinar qué mostrar en la pantalla. Por lo general, devolverás algo de JSX. Tu método render
debe ser una función pura: solo debe calcular el JSX.
De manera similar a los componentes de función, un componente de clase puede recibir información mediante props de su componente padre. Sin embargo, la sintaxis para leer los props es diferente. Por ejemplo, si el componente padre renderiza <Greeting name="Taylor" />
, entonces puedes leer el prop name
desde this.props
, como this.props.name
:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Ten en cuenta que los Hooks (funciones que comienzan con use
, como useState
) no son compatibles dentro de componentes de clase.
Añadiendo estado a un componente de clase
Para agregar estado a una clase, se debe asignar un objeto a una propiedad llamada state
. Para actualizar el estado, se debe llamar a this.setState
.
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = () => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Incrementar edad </button> <p>Hola, {this.state.name}. Tienes {this.state.age} años.</p> </> ); } }
Añadiendo métodos de ciclo de vida a un componente de clase
Hay algunos métodos especiales que puedes definir en tu clase.
Si defines el método componentDidMount
, React lo llamará cuando tu componente se agregue (monte) por primera vez en la pantalla. React llamará a componentDidUpdate
después de que tu componente se vuelva a renderizar debido a cambios en las props o el estado. React llamará a componentWillUnmount
después de que tu componente se haya eliminado (desmontado) de la pantalla.
Si implementas componentDidMount
, generalmente necesitarás implementar los tres ciclos de vida para evitar errores. Por ejemplo, si componentDidMount
lee algún estado o props, también debes implementar componentDidUpdate
para manejar sus cambios, y componentWillUnmount
para limpiar lo que componentDidMount
estaba haciendo.
Por ejemplo, este componente ChatRoom
mantiene una conexión de chat sincronizada con las props y el estado:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Bienvenido al chat {this.props.roomId}!</h1> </> ); } }
Nota que en desarrollo, cuando Strict Mode está activado, React llamará a componentDidMount
, luego llamará inmediatamente a componentWillUnmount
, y luego llamará a componentDidMount
nuevamente. Esto te ayuda a notar si olvidaste implementar componentWillUnmount
o si su lógica no refleja completamente lo que hace componentDidMount
.
Capturando errores de renderizado con un error boundary
Por defecto, si tu aplicación lanza un error durante el renderizado, React eliminará su interfaz de usuario de la pantalla. Para evitar esto, puedes envolver una parte de tu interfaz de usuario en un error boundary. Un error boundary es un componente especial que te permite mostrar alguna interfaz de usuario alternativa en lugar de la que falló, por ejemplo, un mensaje de error.
Para implementar un componente de error boundary, debes proporcionar static getDerivedStateFromError
que te permite actualizar el estado en respuesta a un error y mostrar un mensaje de error al usuario. También puedes implementar opcionalmente componentDidCatch
para agregar algo de lógica adicional, por ejemplo, para registrar el error en un servicio de análisis.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logErrorToMyService(error, info.componentStack);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}
return this.props.children;
}
}
Luego, puedes envolver una parte de tu árbol de componentes con él:
<ErrorBoundary fallback={<p>Something went wrong</p>}>
<Profile />
</ErrorBoundary>
Si Profile
o su componente hijo arroja un error, ErrorBoundary
«capturará» ese error, mostrará una IU de respaldo con el mensaje de error que ha proporcionado y enviará un informe de error de producción a su servicio de informes de errores.
No es necesario envolver cada componente en un error boundary por separado. Al considerar la granularidad de los error boundaries, considere dónde tiene sentido mostrar un mensaje de error. Por ejemplo, en una aplicación de mensajería, tiene sentido colocar un error boundary alrededor de la lista de conversaciones. También tiene sentido colocar uno alrededor de cada mensaje individual. Sin embargo, no tendría sentido colocar un límite alrededor de cada avatar.
Alternativas
Migrando un componente simple de clase a función
Por lo general, definirás los componentes como funciones.
Por ejemplo, supongamos que estás convirtiendo este componente de clase Greeting
en una función:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hola, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Defina una función llamada Greeting
. Aquí es donde moverá el cuerpo de su función render
.
function Greeting() {
// ... move the code from the render method here ...
}
En lugar de this.props.name
, define la prop name
usando la sintaxis de desestructuración y lee directamente de ella:
function Greeting({ name }) {
return <h1>Hola, {name}!</h1>;
}
Aquí tienes un ejemplo completo:
function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
Migrando un componente con estado de clase a funcion
Supongamos que estás convirtiendo este componente de clase Counter
en una función:
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = (e) => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Incrementar edad </button> <p>Hola, {this.state.name}. Tienes {this.state.age} años.</p> </> ); } }
Empieza declarando una función con las variables de estado necesarias:
import { useState } from 'react';
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...
A continuación, convierte los manejadores de eventos:
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
function handleNameChange(e) {
setName(e.target.value);
}
function handleAgeChange() {
setAge(age + 1);
}
// ...
Finalmente, reemplaza todas las referencias que comienzan con this
con las variables y funciones que definiste en tu componente. Por ejemplo, reemplaza this.state.age
con age
, y reemplaza this.handleNameChange
con handleNameChange
.
Aquí tienes el componente completamente convertido:
import { useState } from 'react'; export default function Counter() { const [name, setName] = useState('Taylor'); const [age, setAge] = useState(42); function handleNameChange(e) { setName(e.target.value); } function handleAgeChange() { setAge(age + 1); } return ( <> <input value={name} onChange={handleNameChange} /> <button onClick={handleAgeChange}> Incrementar edad </button> <p>Hola, {name}. Tienes {age} años.</p> </> ) }
Migrando un componente con métodos de ciclo de vida de clase a funcion
Supongamos que estás convirtiendo este componente de clase ChatRoom
con métodos del ciclo de vida a una función:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Bienvenido al chat {this.props.roomId}!</h1> </> ); } }
Primero, verifica que tu método componentWillUnmount
haga lo contrario de componentDidMount
. En el ejemplo anterior, eso es cierto: desconecta la conexión que componentDidMount
establece. Si falta tal lógica, agregala primero.
A continuación, verifica que tu método componentDidUpdate
maneje los cambios en todas las props y el estado que estás usando en componentDidMount
. En el ejemplo anterior, componentDidMount
llama a setupConnection
que lee this.state.serverUrl
y this.props.roomId
. Es por eso que componentDidUpdate
verifica si this.state.serverUrl
y this.props.roomId
han cambiado, y restablece la conexión si lo hicieron. Si falta la lógica de componentDidUpdate
o no maneja los cambios en todas las props y el estado relevantes, corrígelo primero.
En el ejemplo anterior, la lógica dentro de los métodos de ciclo de vida conecta el componente a un sistema fuera de React (un servidor de chat). Para conectar un componente a un sistema externo, describe esta lógica como un solo Effect:
import { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
Esta llamada a useEffect
es equivalente a la lógica en los métodos del ciclo de vida mencionados anteriormente. Si sus métodos del ciclo de vida realizan varias cosas no relacionadas, divídalos en varios efectos independientes. Aquí hay un ejemplo completo con el que puede trabajar:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Bienvenido al chat {roomId}!</h1> </> ); }
Migrando un componente con contexto de clase a funcion
En este ejemplo, los componentes de clase Panel
y Button
leen el contexto desde this.context
:
import { createContext, Component } from 'react'; const ThemeContext = createContext(null); class Panel extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'panel-' + theme; return ( <section className={className}> <h1>{this.props.title}</h1> {this.props.children} </section> ); } } class Button extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'button-' + theme; return ( <button className={className}> {this.props.children} </button> ); } } function Form() { return ( <Panel title="Bienvenido"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }
Cuando los conviertas a componentes de función, reemplaza this.context
con llamadas a useContext
:
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } function Form() { return ( <Panel title="Bienvenido"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }