ReactJS by Facebook is one of the most popular Javascript libraries nowadays.
Many developers love it for many reasons, from efficiency to even its tools. I personally like it because of how components are built in jsx
. In one glance, one can easily see 3 very important things: how it looks like (in the DOM), how it internally works, and how it can connect to other components. As someone who loves building things and investigating how something works, this is a very, very important point for me.
Let’s consider a toggle button. Its React component code will look like below:
// components/ToggleButton.jsx
import React, { Component, PropTypes } from 'react'
class ToggleButton extends Component {
constructor(props) {
super(props)
this.toggle = this.toggle.bind(this)
this.state = {
isPressed: props.isPressed
}
}
toggle() {
this.setState({
isPressed: !this.state.isPressed
})
}
componentDidUpdate(prevProps, prevState) {
if(this.props.onToggle && prevState.isPressed !== this.state.isPressed) {
this.props.onToggle(this.state.isPressed)
}
}
render() {
const buttonClass = this.state.isPressed ? 'pressed' : null
return (
<button className={buttonClass} onClick={this.toggle}>Click me</button>
)
}
}
ToggleButton.defaultProps = {
isPressed: false
}
ToggleButton.propTypes = {
isPressed: PropTypes.bool,
onToggle: PropTypes.func
}
export default ToggleButton
By just looking at this single file, a lot of information can be known.
How it looks like
How a component looks like is very easy to infer. One just needs to look at its render
method.
render() {
const buttonClass = this.state.isPressed ? 'pressed' : null
return (
<button className={buttonClass} onClick={this.toggle}>Click me</button>
)
}
By looking at this method, we can easily know the following about the ToggleButton
component.
- It is a
button
element. - It has the text Click me
- It has the class
pressed
when it is pressed.
Take note that this markup is not really an HTML markup even though it looks similar. The button
tag is not an actual HTML tag but a representation of the Javascript code below:
React.createElement(
button,
{ className: buttonClass, onClick: this.toggle },
'Click me'
)
For those who are new to ReactJS, seeing the markup in the same file as the logic might be weird at first since it’s usually found in a separate HTML file (or another file type, depending on template engine used).
However, the biggest benefit of having the markup with the same file as the logic is that there is no need to navigate a project’s file tree (or the DOM in the browser) just to look for the HTML element that corresponds to a piece of code. The time used for file navigation can be instead used for writing code. This contributes a lot to efficiency.
How it internally works
Abstraction is very important in software engineering, in general. However, there are times when developers need to dive deeper in to the code to investigate a bug, or enhance a feature. Hence, developers need to easily understand how a component works internally.
To understand how a React component works, one must know its properties and lifecycle.
Properties
A component’s properties have 2 types – props
and state
.
props
are properties passed by the parent component, while the state
are properties that are only accessed by the component itself.
Default values of props
can be set by defaultProps
, while the types can be restricted by propTypes
. Using propTypes
adds validation to the component to make sure the data being passed is compatible with the component.
state
cannot be assigned directly, except inside constructor
method where it is initialized. To update the state this.setState
must be used.
Lifecycle
There are 3 major steps in React’s component lifecycle: mounting, updating, and unmounting. It’s straightforward and easy to understand because of the use of will
and did
in method names for methods that get executed around render
.
Detailed information about React’s component lifecycle can be found in the docs.
So how does ToggleButton
really work?
Let’s follow the component lifecycle when interpreting how the component in question works.
constructor(props) {
super(props)
this.toggle = this.toggle.bind(this)
this.state = {
isPressed: props.isPressed
}
}
ToggleButton.defaultProps = {
isPressed: false
}
From this, it can be easily seen that props.isPressed
(from the parent component) is assigned as the initial value for state.isPressed
. If parent doesn’t pass anything, false
is assigned by default.
Next, the component is rendered:
render() {
const buttonClass = this.state.isPressed ? 'pressed' : null
return (
<button className={buttonClass} onClick={this.toggle}>Click me</button>
)
}
When the user clicks on the button, it inverts isPressed
state, and renders again. It toggles the existence of the pressed
HTML class of the button.
toggle() {
this.setState({
isPressed: !this.state.isPressed
})
}
Since the button is toggled (and therefor updated), the onToggle
function from the parent is called.
componentDidUpdate(prevProps, prevState) {
if(this.props.onToggle && prevState.isPressed !== this.state.isPressed) {
this.props.onToggle(this.state.isPressed)
}
}
As demonstrated above, figuring out how a component works internally is very easy to do because the steps the component take is very clear.
How it can connect to other components
Knowing how ToggleButton
can connect to other components can easily be seen by just looking at defaultProps
and propTypes
.
ToggleButton.defaultProps = {
isPressed: false
}
ToggleButton.propTypes = {
isPressed: PropTypes.bool,
onToggle: PropTypes.func
}
The following information are easily obtainable:
- It accepts
isPressed
andonToggle
properties, both optional. (ifisRequired
is changed, it’s a required property) - It has
false
as default forisPressed
. - It only accepts
boolean
value forisPressed
, andfunction
foronToggle
.
Since the needed properties are now known, the ToggleButton
component can be used inside another component:
import React, { Component, PropTypes } from 'react'
import ToggleButton from 'components/ToggleButton'
class ParentComponent extends Component {
render() {
const onToggle = () => console.log('toggled')
return (
<div>
<p>I have the button</p>
<ToggleButton isPressed onToggle={onToggle} />
<div>
)
}
}
And yes, ToggleButton
is used just like how an HTML tag is used!
Seeing components used like this makes it look neat. It’s also easy to see where a component and logic goes in your DOM.
Conclusion
ReactJS, for me, is built for builders like myself. The component is well designed because of easy integration with other components. We can also easily ‘tinker’, if needed be, since we can easily know a lot (if not all) of information about that component by just looking at its file.
It reminds me of the Lego blocks I used to play when I was a child. After all, maybe the biggest reason I enjoy working with ReactJS is that it reminds me of the fun I had as a child.