Categories
Uncategorized

State & Lifecycle in React.JS

Lets create a simple clock function to do encapsulation of clock function:

function Clock(props) {
return ( <h1> Date is {props.date.toLocaleTimeString()}.</h1> );
}

This function will fetch value from component Clock, which we will define directly while rendering output:

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

In the end we add ‘setInterval’ function:

setInterval(tick, 1000);


Converting function to class: In above, ‘Clock()’ itself is not a fully functional in itself, half of its code is linked in tick() function. To work on it first lets convert above Clock() function into ES6 class form. It can be done in following way:

  1. Create an ES6 class, with the same name, that extends React.Component.
  2. Add a single empty method to it called render().
  3. Move the body of the function into the render() method.
  4. Replace props with this.props in the render() body.
  5. Delete the remaining empty function declaration.

It has been shown below:

class Clock extends React.Component {
render(){
return ( <h1> Date is {this.props.date.toLocaleTimeString()}.</h1> );
}
}

Rest of the code remains same. This code can be replaced with ‘Clock(props)’ function above to make it work. 


Adding local state to a class: This can be done is three steps.

1) Create a constructor function inside class and add this code to it: 

constructor(props) {
super(props);
this.state = {date: new Date()};
}

2) Replace ‘props’ in render function with ‘state’: 

render(){
return ( <h1> Date is {this.state.date.toLocaleTimeString()}.</h1> );
}

3) Remove the Date prop from render function: 

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

It will make the overall code to look like this:

class Clock extends React.Component {

constructor(props) {
super(props);
this.state = {date: new Date()};
}

render(){
return ( <h1> Date is {this.state.date.toLocaleTimeString()}.</h1> );
}
}

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

setInterval(tick, 1000);

In above changes most of the code is in class ‘Clock’ and render function is just calling this whole class. 


Adding Lifecycle method to a Class: In above code changes done so far, reactDOM.Render is still inside tick() function. So this auto-refresh functionality should be added to class ‘Clock’ itself, so that when this class is not getting used, it do not put load on DOM. 

To set up a timer only when Clock class is called, it is known as ‘mounting’ and when the Clock is removed, timer should be cleared, it is know as ‘unmounting’ in React. This can be done by adding three functions in class.

1) First add function componentDidMount() and add following code in it: 

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

2) Then add function Unmount function componentWillUnmount() to clear timer, as follows:

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

3) After that create a tick function, to set state on date variable: 

tick() {
this.setState({
date: new Date()
});
}

Finally, we can remove the tick function from reactDOM and remove setInterval() function:

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

Overall code looks like this: 

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 ( <h1> Date is {this.state.date.toLocaleTimeString()}.</h1> );
}
}

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


Let us take code to next level and create multiple independent clocks with above made class. For it let us make a function named App, outside this class:

function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}

And in ReactDOM, render the App() function: 

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

Now the code is ready and encapsulated. It is not accessible to any outside component. It is accessible to only components that owns or sets it. 


Additionally, a component may choose to pass its state as ‘props’ down to its children component. To test it, let us replace {this.state.date.toLocaleTimeString()} inside render function with following code: 

render(){
return ( <h1> Current time <FormattedDate date={this.state.date} /></h1> );
}

Now we have a ‘FormattedDate’ component and it can be manipulated by creating a function for it outside class, like shown here:

function FormattedDate(props) {
return <h5> is {props.date.toLocaleTimeString()}.</h5>;
}

It makes the overall code to like: 

function FormattedDate(props) {
return <h5> is {props.date.toLocaleTimeString()}.</h5>;
}

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 ( <h1> Current time <FormattedDate date={this.state.date} /></h1> );
}
}

function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}

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

 

Leave a Reply

Your email address will not be published. Required fields are marked *