React.js's state management approach allows systematic implementation of a wide variety of user experiences. One such user experience technique is telling the user that something is happening or is loading in the background when a button is clicked. To achieve this, we'd like to have a boolean state value that governs the visibility of user interface components. That is, if the state value is true
then the components are disabled. Otherwise, the components are disabled. That same value can also be used to determine if a section of the app will display a loading message or any visual component for that matter.
Supposed you're creating a SearchComponent
that contains two major input elements:
You'll then control the disabled
attribute of these two elements with an isDisabled
boolean state.
In your component's constructor, go ahead and define the isDisabled
state with an initial value of false
. This tells the user that they are free to input stuff in the text input and click the submit button.
1import React from 'react';
2
3export default class SearchComponent extends React.Component {
4 constructor(props) {
5 super(props);
6
7 this.state = {
8 isDisabled: false
9 }
10 }
11}
Create your component's render()
method that returns the form itself with the two UI elements. Copy the following function and paste it within the SearchComponent
. In practice, it's usually found as the last method of a React.js component.
1render() {
2 return (
3 <div>
4 <input type="text" disabled={this.state.isDisabled} />
5 <button disabled={this.state.isDisabled}>
6 Submit Query
7 </button>
8 </div>
9 );
10}
Embed the value of this.state.isDisabled
as a value of the disabled
attribute via JSX as wrapped by {}
. Since its initial value is false
, users can then proceed to input text in it.
1<input type="text" disabled={this.state.isDisabled} />
The same goes for the button for submitting a query.
1<button disabled={this.state.isDisabled}>
2 Submit Query
3</button>
The next thing you have to do is to bind a function that will update the state value of a component by calling this.setState()
, where this
is a reference to the instance of the React.js component. Remember that in React.js, a call to this.setState()
will force a re-render of the component with the newly updated values. The function will look like the following:
1handleSubmitClicked() {
2 this.setState({
3 isDisabled: true
4 });
5}
Given your event handler, you'll bind the function to your button's onClick
attribute:
1<button
2 disabled={this.state.isDisabled}
3 onClick={this.handleSubmitClicked.bind(this)}
4>
5 Submit Query
6</button>
Invoke the .bind(this)
function in order to retain the value for this
, which is a reference to the instance of the component. This way (pun not intended), the this
inside the logic of handleSubmitClicked()
will always retain the value of the component's instance, thus allowing the setState()
to be called from it.
Since handlSubmitClicked()
updates the state of isDisabled
to true
, it will force a call to the render()
method of the component, causing the input elements' disabled
attribute to have a value of true
. As a result, this will create an effect that tells the user that something is happening after the button was clicked.
Once the process is finished, you can tell the user that they're free to input or modify the current text field. Do this by creating another event handler function that does the opposite—that is, it enables the UI components:
1enableComponents() {
2 this.setState({
3 isDisabled: false
4 });
5}
To simulate that "something is happening," add code in the handleSubmitClicked()
that waits three seconds before firing a function which in turn will call enableComponents()
.
1handleSubmitClicked() {
2 this.setState({
3 isDisabled: true
4 });
5
6 setTimeout(
7 function() {
8 this.enableComponents()
9 }.bind(this),
10 3000
11 );
12}
Notice that you'll call .bind(this)
once again against the function that is the first argument to setTimeout()
. This will allow this
to retain its value as the reference to the instance of this component, allowing a call to be made to enableComponents()
. Normally, this timeout code will be replaced by actual processing of the user input, which will eventually call enableComponents()
once done.
Your final component form will look like the following:
1import React from 'react';
2
3export default class SearchComponent extends React.Component {
4 constructor(props) {
5 super(props);
6
7 this.state = {
8 isDisabled: false
9 }
10 }
11
12 handleSubmitClicked() {
13 this.setState({
14 isDisabled: true
15 });
16
17 setTimeout(
18 function() {
19 this.enableComponents()
20 }.bind(this),
21 3000
22 );
23 }
24
25 enableComponents() {
26 this.setState({
27 isDisabled: false
28 });
29 }
30
31 render() {
32 return (
33 <div>
34 <input type="text" disabled={this.state.isDisabled} />
35 <button
36 disabled={this.state.isDisabled}
37 onClick={this.handleSubmitClicked.bind(this)}
38 >
39 Submit Query
40 </button>
41 </div>
42 );
43 }
44}
Try this component out and notice that upon clicking Submit Query, both the input and button elements will disable, and after three seconds will be enabled again.
This guide demonstrated a simple way to communicate to a user that something is happening after clicking a button by maintaining a boolean state variable that serves as a value for the visibility of the UI. Try to see if you can incorporate this technique to your own stateful React component by having a single state variable govern the accessibility of your interface. Some suggestions are:
true
. Otherwise, hide the text or visualization.enableComponents()
after a successful AJAX call within handleSubmitClicked()