> Manuales > Manual de React

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 antes de la primera renderización del componente, es decir, 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

Vamos a comenzar viendo cómo se usan los métodos de renderizado con la variante de creación de componentes a partir clases ES6 y luego veremos la alternativa en ES5 mediante createClass().

Para ambas alternativas debemos tener en cuenta los siguientes procedimientos comunes:

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

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, cuando se ejecuta 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) {
    super(...args)
    console.log('Ejecuto constructor', ...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.

Inicialización predeterminada de propiedades y estado con createClass (ES5)

Si usamos el mecanismo de createClass, la inicialización de los componentes se realiza de manera ligeramente diferente, por medio de dos métodos específicos que tenemos que crear en el componente, uno para inicializar las propiedades y otro para el estado. React se encargará de invocar una única vez la inicialización de las propiedades, independientemente del número de componentes creados de esa clase, y de invocar una vez para cada componente el método de inicialización del estado.

Nota: Como hemos señalado en varios momentos del manual de React, el método createClass no es el recomendado actualmente para la creación de componentes. Por ello esta parte quizás te la puedes saltar, si es que todos tus componentes están desarrollados mediante clases ES6, pues será indiferente para ti.

Estos dos métodos 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.

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

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual