Propiedades y estado predeterminado en componentes React

  • Por
Cómo definir predeterminados para las propiedades de los componentes React, así como para su estado.

En capítulos anteriores del Manual de React tuvimos la ocasión de aprender a crear, y usar, propiedades en los componentes. También analizamos el estado de los componentes y aprendimos a crear componentes statefull, con sus métodos para definir y alterar el estado, así como representar las vistas dependiendo del estado.

En este capítulo vamos a analizar los modos mediante los cuales podemos definir tanto los valores predeterminados de las propiedades, como del estado. Nos detenemos en este punto porque, dependiendo de cómo se creen los componentes, el modo de trabajo será diferente.

Antes de comenzar cabe simplemente recordar las variantes básicas para la creación de componentes, que ya conoces:

Primer render

Estas operaciones de carga de valores predeterminados en propiedades y estado se realizan guiados por unos métodos específicos de React, que se ejecutan durante la primera renderización del componente, justo antes de representarse en la página.

Como primer render nos referimos a la primera vez que se representa el componente dentro de la página, y se inyecta en el DOM del navegador. Cuando ocurre esa operación de renderizado, el componente debe tener tanto sus propiedades como su estado inicializados.

Nota: Estos métodos están muy ligados al ciclo de vida de los componentes, puesto que se ejecutan en etapas muy concretas de la vida de un componente. Analizaremos con detalle el ciclo de vida en el próximo artículo.

Métodos para definir propiedades y estado predeterminado

Si queremos indicar tanto propiedades como estado con valores predeterminados debemos usar los siguientes métodos.

Vamos a comenzar viendo cómo se usan los métodos de renderizado con la variante de creación de componentes a partir de React.createClass(). Son dos métodos y los vamos a ver por orden de ejecución.

getDefaultProps()

Este método se ejecuta primero y sirve para generar valores por defecto para las propiedades de un tipo de componente. Con tipo de componente nos referimos a todas las instancias que un componente puede generar. Por ejemplo, si un componente se usa 5 veces, este método se ejecutará una única vez, antes de comenzar a instanciar elementos concretos de ese componente.

Este método debe devolver un objeto, con el conjunto de propiedades cuyos valores predeterminados se quiera definir.

Los valores predeterminados en las propiedades funcionan de la siguiente manera.

Si al usar el componente se indican los valores de las propiedades, se toman esos valores dentro de la instancia del componente. No se indicaron los valores de esas propiedades al usar el componente, se crearán igualmente esas propiedades, cargando sus valores definidos mediante getDefaultProps().

Este método solo es posible usarlo cuando estamos trabajando con la variante de creación de componentes React.createClass().

getInitialState()

Este método se ejecuta después de haberse definido las propiedades por defecto. Sirve para inicializar el estado inicial de un componente y solamente funciona en componentes creados mediante React.createClass(). A diferencia de getDefaultProps(), este método se ejecuta una vez por instancia del componente.

El objeto que devuelva getInitialState() será lo que se inicialice como estado del componente.

Veremos ahora un ejemplo sobre cómo se podrían realizar estas inicializaciones mediante el método de creación de componentes de React.createClass().

var ComponenteInicializacion = React.createClass({
  getDefaultProps: function() {
    console.log('Ejecuto getDefaultProps')
    return {
      propiedad: 'Valor por defecto de una propiedad'
    }
  },

  getInitialState: function() {
    console.log('Ejecuto getInitialState');
    return {
      estado: 'inicializado en getInitialState'
    }
  },

  render: function() {
    console.log('Ejecuto render')
    return (
      <div>
        <p>Componente con propiedades y estado inicializado</p>
        <p>Estado: {this.state.estado}</p>
        <p>Propiedad: {this.props.propiedad}</p>
      </div>
    )
  }

})

Si usas este componente varias veces observarás gracias a los console.log que primero se inicializan las propiedades por defecto, una sola vez, y luego se inicializa el estado y se renderiza tantas veces como componentes hayas generado.

var anclaje = document.getElementById('anclaje')
ReactDOM.render(
  <div>
    <ComponenteInicializacion />
    <ComponenteInicializacion />
  </div>
  , anclaje)

Ahora te dejamos un archivo html completo donde podrás ver el componente en su declaración y funcionamiento, que podrás usar en un entorno vacío, sin necesidad de configurar transpiladores. Recuerda que esta alternativa no es la correcta para usar React en un entorno de producción, como se explicó en el artículo Comenzar con ReactJS desde un entorno de desarrollo vacío.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Inicializar componentes con createClass</title>
</head>
<body>
  <div id="anclaje"></div>

  <script src="https://unpkg.com/react@15.3.2/dist/react.js"></script>
  <script src="https://unpkg.com/react-dom@15.3.2/dist/react-dom.js"></script>
  <script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
  
  <script type="text/babel">
    var ComponenteInicializacion = React.createClass({
      getDefaultProps: function() {
        console.log('Ejecuto getDefaultProps')
        return {
          propiedad: 'Valor por defecto de una propiedad'
        }
      },

      getInitialState: function() {
        console.log('Ejecuto getInitialState');
        return {
          estado: 'inicializado en getInitialState'
        }
      },

      render: function() {
        console.log('Ejecuto render')
        return (
          <div>
            <p>Componente con propiedades y estado inicializado</p>
            <p>Estado: {this.state.estado}</p>
            <p>Propiedad: {this.props.propiedad}</p>
          </div>
        )
      }

    })

    var anclaje = document.getElementById('anclaje')
    ReactDOM.render(
      <div>
        <ComponenteInicializacion />
        <ComponenteInicializacion />
      </div>
      , anclaje)
  
  </script>
  
</body>
</html>

Sirva entonces el anterior código solo para motivos de pruebas. Se podría ejecutar perfectamente haciendo doble clic sobre el archivo HTML, sin necesidad de un servidor web. Ten en cuenta que nuestro método preferido es el siguiente, en el que realizaremos lo mismo desde un entorno completo con Create React App y clases ES6.

Mecanismo de inicialización de propiedades y estado con clases ES6

Cuando estamos trabajando con clases ES6 estos mecanismos varían un poco. Los métodos getDefaultProps() y getInitialState() no te funcionarán. Si los intentas usar observarás mensajes del compilador y en la consola.

En el caso de la inicialización de propiedades, en componentes creados con clases de ES6, se debe realizar definiendo una propiedad "defaultProps" en la clase que implementa el componente. En el caso de la inicialización del estado, la operativa se realiza en el constructor. Se verá claramente con un ejemplo enseguida.

Nota: En el caso de la inicialización de propiedades, como se realiza una única vez para todos los componentes de un tipo, no tiene sentido realizarlo en el constructor, puesto que en ese caso se realizaría para cada una de sus instancias. Por tanto, en el constructor ya estarán inicializadas las propiedades con sus valores por defecto, o aquellos definidos al usar el componente.

En la alternativa de creación de componentes mediante clases ES6 el código que tendríamos que generar para la inicialización de las propiedades y estado sería el siguiente:

import React from 'react'

export default class CicloVida extends React.Component {
  constructor(...args) {
    console.log('Ejecuto constructor', ...args)
    super(...args)
    this.state = {
      estado: 'Inicializado en el constructor'
    }
  }

  render() {
    return (
      <div>
        <p>Componente con propiedades y estado inicializado</p>
        <p>Estado: {this.state.estado}</p>
        <p>Propiedad: {this.props.propiedad}</p>
      </div>
    )
  }
}

CicloVida.defaultProps = {
  propiedad: 'Valor por defecto definido para la propiedad'
}

Como estarás observando, la inicialización de propiedades se hace una vez definida la clase, mediante una propiedad que usamos dentro de la propia clase. Al no estar en el código de la clase, se ejecutará una única vez.

Ya para la inicialización de estado, se define en el constructor, con lo que se ejecutará para cada componente instanciado de manera independiente. Esto lo vimos con detalle en el artículo sobre el estado de los componentes.

Continuaremos este manual con el ciclo de vida de los componentes, algo cuyas primeras trazas ya hemos empezado a ilustrar con este artículo.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir