Props vs State en React.js

Props vs State en React.js

Introducción

El concepto de state (estado) en React, nos permite pasar de una IU estática y definitiva, a una IU dinámica, fluída y que cambia constantemente según la interacción del usuario.

Para entender este artículo son necesarios conocimientos previos de Componentes y JSX así como funciones de orden superior ( map() ),funciones de flecha y event listeners.

Contexto

Como ejemplo para entender el estado, voy a usar un componente donde disponemos un array de strings e iteramos sobre dicho array y generamos un párrafo para cada uno de sus elementos y los renderizamos en pantalla.

import React from 'react';
import ReactDOM from 'react-dom';

function App() {
    const arrayDeCosas = ["Item 1", "Item 2"];

    const elementosP = arrayDeCosas.map(item => <p key = {item}>{item}</p>);

    return (
        <div>
            <button>Add Item</button>
            {elementosP}
        </div>
    )
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <App />
);

react state exercises.png

Como habrás podido darte cuenta, este componente no tiene nada de interacción así que vamos a añadir un manejador de eventos para que cada vez que presionemos el botón, se añada un nuevo elemento al array.

import React from 'react';
import ReactDOM from 'react-dom';


function App() {
    const arrayDeCosas = ["Elemento 1", "Elemento 2"]
    const elementosP = arrayDeCosas.map(thing => <p key={thing}>{thing}</p>)

    const handleButton = () => {
        arrayDeCosas.push(`Elemento ${arrayDeCosas.length + 1}`);
        console.log(arrayDeCosas);
    }

    return (
        <div>
            <button onClick = {handleButton }>Add Item</button>
            {elementosP}
        </div>
    )
}

ReactDOM.render(<App />, document.getElementById('root'));

Como era de esperarse,al hacer clic en el botón, se añaden nuevos elementos al array pero la página no se actualiza:

react state exercises 2.png

Esto nos lleva al propósito de este artículo: React no mira a los arrays locales dentro de nuestro componente para determinar si algo debe ser re-renderizado en pantalla o no.

En otras palabras,React no mira a los arrays para determinar si nuestro return() debe ejecutarse otra vez con los valores actualizados de arrayDeCosas.

Para empoderarnos del acercamiento declarativo de React, todo lo que tenemos que hacer es asegurarnos que los datos se actualizan correctamente y React automaticamente "reaccionará" (lol) a estos cambios y actualizará la IU para que muestre qué ha cambiado.

Para disfrutar de esta característica necesitamos acceder a algo llamado "State" (estado). Cuando actualizamos el estado (que son valores que guardamos dentro del componente) esto hace que React actualice el IU basado en esos cambios.

Props vs State

Props

Cuando hablamos de "props" hablamos de las propiedades que son pasadas a un Componente para que este funcione correctamente o con objetivo de configurar dicho Componente , de manera similar a una función que recibe parámetros. Un componente que recibe props, no se le permite cambiar estas propiedades (son imutables), de la misma manera que una función pierde su sentido su cambia los parámetros que le son pasados.

Supongamos que tengo una función literal en JavaScript donde recibe dos parametros a y b

function sumaDosNumeros(a, b) {
    return a + b;
}

sumaDosNumeros(1,2); // 3

El punto aqui es que no tendría sentido que reasignaramos los valores de a y b una vez recibidos dentro de la función, destruiría completamente el propósito de la función.

function sumaDosNumeros(a, b) {
    a = 42;
    return a + b; 
}

sumaDosNumeros(1,2); // 44

De la misma forma, no tendría sentido que cambiaramos las props recibidas en un Componente dentro del cuerpo del componente (que también es una función).

function Navbar(props) {
    props.coverImage = "Otra cosa"
}

Esto no significa que no pueda tener por ejemplo un componente al que le estamos pasando una prop inicial dentro de la etiqueta del componente, y que esta cambie según una interacción del usuario como por ejemplo un clic en un elemento HTML.

/* Por ejemplo una propiedad para determinar si un componente es mostrado en modo nocturno o no */
<Navbar darkMode={true}  />

State

De diferente modo, un estado se refiere a los valores que son administrados por el componente, similar a variables declaradas dentro de una función literal en JavaScript. Cada vez que cambiamos valores que deben ser guardados/renderizados, debemos usar un estado.

Tracemos un paralelo state y funciones en Vanilla JavaScript:

function saludo(nombre) {
    const fecha= new Date()
    const horas= date.getHours()

    let parteDelDia
    if(horas >= 4 && horas < 12) {
        parteDelDia = "Buenos días"
    } else if(horas >= 12 && horas < 17) {
        parteDelDia = "Buenas tardes"
    } else if(horas >= 17 && horas < 20) {
       parteDelDia = "Buenas tardes"
    } else {
        parteDelDia = "Buenas noches"
    }

    return `${parteDelDia}, ${nombre}!`
}

console.log(saludo("Pablo"))

El punto aquí es que nuestra función espera un parámetro (nombre), este parámetro no es algo que queramos cambiar dentro del cuerpo de la función.

Pero si queremos crear nuevos valores para usarlos y combinarlos con los parámetros recibidos. De manera similar, en React no tomaremos props y las cambiaremos dentro del cuerpo del Componente, y los valores adicionales creados dentro del Componente son manejados atraves del state.