"Structural Basics of ReactJS," or "PLEASE NO, NOT ANOTHER REACTJS PRIMER"
Grant
Posted on July 13, 2020
Yes, it's true. This is another ReactJS primer. But maybe, just maybe, this will be the one that makes it sink in for you. (It was for me, after all.)
Components
Components are the building blocks in ReactJS. At the most basic level, they take in data and return a React element, or, the thing that should appear on the screen. What's convenient is the data the function takes in is always called the same thing: props
. Here's a very basic example:
const Greet = props => {
return <h1>Hello from {props.location}</h1>;
}
Alternately, an ES6 class can accomplish the same thing:
class Greet extends React.Component {
render() {
return <h1>Hello from {this.props.location}</h1>;
}
}
Notice the use of capitalization for the component name Greet
. The reason for this convention is to distinguish it from a typical DOM tag, such as the <h1>
above. These must be distinguished because a component can also be referred to as an element:
const Greet = (props) => {
return <h1>Hello from {props.location}</h1>;
}
const element = <Greet location="New Orleans" />;
ReactDOM.render(
element,
document.getElementById('root')
)
In the example above, element Greet
has a property location
, which is passed to the component Greet
through the props
object, the one and only vehicle for data in any relationship of this nature in React. The Greet
component formulates the data it receives through props
into an html-y element, which ReactDOM renders to the DOM. (The html-y business is thanks to JSX, JavaScript XML, a syntax extension to JavaScript. It's helpful, but required.) This example renders to the page "Hello from New Orleans."
Components can also be referred to by other components, allowing for further abstracting away of the structure:
const Greet = props => {
return <h1>Hello from {props.location}</h1>;
}
const App = () => {
return (
<div>
<Greet location="Mid-city, New Orleans" />
<Greet location="Uptown, New Orleans" />
<Greet location="French Quarter, New Orleans" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
In the example above, component App
—a common moniker for the highest level component containing all other components—returns three instances of component Greet
, each with a different value. Notice in component App
the use of parentheses, another common pattern in ReactJS. The parentheses "collect" all the components to be returned so JavaScript will return multiple lines.
State
So far, all the examples we've looked at have been stateless. This means they have not had to keep track of any data changes or re-render. Let's practice that now by refactoring Greet
to initialize state:
class Greet extends React.Component {
constructor(props){
super(props);
this.state = {
location: "the West Bank"
};
this.updateLocation = this.updateLocation.bind(this);
}
updateLocation() {
this.setState({
location: "the East Bank"
});
}
render() {
return <h1>Hello from {this.state.location}</h1>;
}
}
Component Greet
is now a class with a constructor (notice the call to super
like any proper subclass!) which sets state using keyword this
. Likewise, the method, updateLocation
, is bound with keyword this
within the constructor. Inside the method itself is the crucial part that often goes wrong. Here, the setState
react method must be used, not the logical presumption of this.state.location = "new location"
. Finally, the return element is moved inside of the render
method, and instead of using props.location
, uses this.state.location
. (Side note: notice the use of curly braces around this.state.location
. These allow the contained code to be interpreted as javascript instead of React, another commonly used tool.)
Finally, let's add a button to click to update the location:
render() {
return (
<div>
<h1>Hello from {this.state.location}</h1>
<button onClick={this.updateLocation}>Change location</button>
</div>
)
}
And now to tie it together:
class Greet extends React.Component {
constructor(props){
super(props);
this.state = {
location: "the West Bank"
};
this.updateLocation = this.updateLocation.bind(this);
}
updateLocation() {
this.setState({
location: "the East Bank"
});
}
render() {
return (
<div>
<h1>Hello from {this.state.location}</h1>
<button onClick={this.updateLocation}>Change location</button>
</div>
)
}
}
const App = () => {
return (
<div>
<Greet />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
A summary:
- Component
Greet
'slocation
property resides in itsstate
, which can be changed when the button element calls theupdateLocation
method. (Props are still passed down here fromApp
but are no longer used since thelocation
property now lives instate
.) - The current value of
location
is rendered with the text in the<h1>
element. - Component
App
renders componentGreet
. -
ReactDOM
rendersApp
to the page.
Hopefully, breaking this into small components (see what I did there) helps to "see" the patterns and where the dots connect. To be fair, it's never this easy to picture in reality. References are obscured by being located across numerous files and keeping track of them can become dizzying. But the more these structures become second nature, the faster you'll be comfortable diving into a full scale program. Keep at it!
Posted on July 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.