Bruno R

Estado y ciclo de vida

x
portfolio-next-l5vb64p5k-bandikyu.vercel.app

Considerando el ejemplo del reloj, se aprendio solo una manera de actualizar la interfaz, invocando ReactDOM.render() nuevamente para que cambie el resultado del renderizado.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      
<h2>It is {new Date().toLocaleTimeString()}.</h2>

    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

Para avanzar en el proceso de la creacion de un componente totalmente retutilizable y encapsulado, empezamos primero por crear el componente (Clock):

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      
<h2>It is {props.date.toLocaleTimeString()}.</h2>

    </div>
  );
}

function tick() {
  ReactDOM.render(
    
<Clock date={new Date()} />
,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

Pero lo que se quiere lograr es un componente actualizable que no dependa de ninguna funcion a la hora de hacer ReactDOM.render, algo asi:

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

Para lograr esto, necesitariamos agregar estados al componente Clock.

Los estados son similiares a las props, pero es privado(?) y esta completamente controlado por el componente.

Convertir una funcion en una clase

Al parecer para utilizar la caracteristica de los estados, el componente debe estar definido como una clase.

Para convertir un componente de funcion en clase:

Crear una 
Agregar un único método vacío llamado 
Mover el cuerpo de la función al método 
Reemplazar 
Borrar el resto de la declaración de la función ya vacía.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Agregar el estado local a una clase

Cambiando date de props a state:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
 
Se nota como pasamos props al constructor base:

Y por ultimo se elimina la propiedad date en el componente cuando renderizmos con ReactDOM.render():

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

Resultado final

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }


  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

Agregar metodos de ciclo de vida a una clase

En aplicaciones con muchos componentes en necesario el liberar recursos de los componentes destruidos, para esto se busca configurar un temporizador cada vez que Clock se renderice en pantalla por “primera vez”. A esto se le llama <<Montaje>>componentDidMount()en react.

Tambien queremos borrar ese temporizador cada vez que el DOM producido por Clock se elmine, esto se llamaria <<Desmontaje>> componentWillUnmount()en react.

Se pueden declarar metodos especiales en el componente de clase cuando este se monta o desmonta.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
  }

  componentWillUnmount() {
  }


  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

El metodo componentDidMount() se ejecuta despues que la salida del componente a sido renderizada en el DOM. Osea una vez se cargue el elemento, se iniciara este metodo. Entonces dentro de este metodo es un buen lugar para inicializar un temporizador jeje:

componentDidMount() {
	this.timerID = setInterval(
		() => this.tick(),
		1000
	);

}

Eliminamos el temporizador en el metodo de ciclo de vida componentWillUnmount()

componentWillUnmount() {
    clearInterval(this.timerID);
  }

Y por ultimo el metodo tick() con this.setState() para programar actualizaciones al estado local del componente cada 1 segundo

Resultado final:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {    
		this.setState({date: new Date()});
	}
	render() {
    return (<div>        
							<h1>Hello, world!</h1>        
							<h2>It is {this.state.date.toLocaleTimeString()}.</h2>      
						</div>);
  }
}

ReactDOM.render(
  <Clock />,

  document.getElementById('root')
);

Repasemos rápidamente lo que está sucediendo y el orden en que se invocan los métodos:

Cuando se pasa 
React invoca entonces al método 
Cuando la salida de 
Cada segundo el navegador invoca al método 
Si el componente 

Usar el estado correctamente

setState() Important tres cosas importantes para tener en cuenta a la hora de usar setState():

No modifiques el estado directamente

Las actualizaciones de estado pueden ser asincronas

Las actualizaciones de estado se fusionan

Los datos fluyen hacia abajo

Ni los componentes padres o hijos saben si un deteminado componente tiene o no estado, y tampoco consideran si fue definido mediante una funcion o una clase.

Por esta razon se dice que el estado es local (encapsulado), no es accesible desde otro componente exepto aquel que lo posee y lo asigna.

Lo que si se puede hacer para “compartir” estados mediante las props a los componentes hijos:

<FormattedDate date={this.state.date} />
/*fijate como la props date de FormattedDate recibe el valor del estado del
componente padre con this.state.date*/

El componente FormattedDate recibira date en sus props sin saber de donde proviene como se venia diciendo; pude ser del estado de date, o sus props, o de datos ingresados de manera estatica.

function FormattedDate(props) {
  return <h2>It is {
props.date
.toLocaleTimeString()}.</h2>;
}
//aca estaria el componente FormattedDate recibiendo de manera anonima los datos xD

Esto es conocido como flujo de datos <desecendente> o <unidireccional>. Cualquier estado es propiedad de algun componente especifico, y cualquier dato o interfaz de usuario solo puede afectar a los componentes debajo de estos en el arbol

Glosario de palabras

Buscar conceptos