Bruno R
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.
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:
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
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') );
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:
setState() Important tres cosas importantes para tener en cuenta a la hora de usar setState():
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