<!doctype html>
<html>
<head>
	<meta charset="utf-8" />

	<title>
		setState(), shouldComponentUpdate(), and render() Timing In ReactJS
	</title>

	<link rel="stylesheet" type="text/css" href="./demo.css"></link>
</head>
<body>

	<h1>
		setState(), shouldComponentUpdate(), and render() Timing In ReactJS
	</h1>

	<div id="content">
		<!-- App will be rendered here. -->
	</div>


	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/reactjs/react-0.13.3.min.js"></script>
	<script type="text/javascript">

		// I manage the root application component.
		var Demo = React.createClass({

			// I return the initial state of the component.
			getInitialState: function() {

				return({
					status: "Pre-timeout",
					count: 0
				});

			},


			// ---
			// PUBLIC METHODS.
			// ---


			// I get called once, on the client, when the component has been rendered
			// in the DOM.
			componentDidMount: function() {

				setTimeout( this.handleTimeout, 1000 );

			},


			// I handle the click event.
			// --
			// CAUTION: Since this is powered by the onClick prop of the link element,
			// it is managed through ReactJS' event delegation and allows state updates
			// to be queued and flushed asynchronously.
			handleClick: function( event ) {

				console.warn( "handleClick()." );
				console.log( "handleClick() - BEFORE setState()." );

				var currentCount = this.state.count;

				this.setState({
					count: ++currentCount
				});

				this.setState({
					count: ++currentCount
				});

				console.log( "handleClick() - AFTER setState()." );

			},


			// I handle the timeout event (callback).
			// --
			// CAUTION: Since this is powered by the setTimeout() method, it cannot be
			// managed by ReactJS' event delegation system. As such, the state changes
			// cannot be queued and must be applied synchronously.
			handleTimeout: function() {

				console.warn( "handleTimeout()." );
				console.log( "handleTimeout() - BEFORE setState()." );

				this.setState({
					status: "Post-timeout"
				});

				this.setState({
					count: ( this.state.count + 1 )
				})

				console.log( "handleTimeout() - AFTER setState()." );

			},


			// I return the virtual DOM based on the current component state.
			render: function() {

				console.log( "render()." );

				return(
					React.DOM.div(
						null,
						React.DOM.p(
							null,
							React.DOM.strong( null, "Status:" ),
							" ",
							this.state.status
						),
						React.DOM.p(
							null,
							React.DOM.strong( null, "Count:" ),
							" ",
							this.state.count
						),
						React.DOM.p(
							null,
							React.DOM.a(
								{
									onClick: this.handleClick
								},
								"Increment count"
							)
						)
					)
				);

			},


			// I determine if the virtual DOM should be recalculated based on the
			// delta in the incoming state and props collections.
			shouldComponentUpdate: function( newProps, newState ) {

				console.log( "shouldComponentUpdate()." );
				console.log(
					". . . shouldComponentUpdate() - Status: new( %s ) vs. current( %s ).",
					newState.status,
					this.state.status
				);
				console.log(
					". . . shouldComponentUpdate() - Count: new( %s ) vs. current( %s ).",
					newState.count,
					this.state.count
				);

				return( true );

			}

		});


		// --------------------------------------------------------------------------- //
		// --------------------------------------------------------------------------- //


		// Render the root Demo and mount it inside the given element.
		React.render(
			React.createElement( Demo ),
			document.getElementById( "content" )
		);

	</script>

</body>
</html>