DEV Community

Grant
Grant

Posted on

"Structural Basics of ReactJS," or "PLEASE NO, NOT ANOTHER REACTJS PRIMER"

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>;
}
Enter fullscreen mode Exit fullscreen mode

Alternately, an ES6 class can accomplish the same thing:

class Greet extends React.Component {
  render() {
    return <h1>Hello from {this.props.location}</h1>;
  }
}
Enter fullscreen mode Exit fullscreen mode

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')
)
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode

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>;  
    }  
}
Enter fullscreen mode Exit fullscreen mode

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>     
  )  
}
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode

A summary:

  1. Component Greet's location property resides in its state, which can be changed when the button element calls the updateLocation method. (Props are still passed down here from App but are no longer used since the location property now lives in state.)
  2. The current value of location is rendered with the text in the <h1> element.
  3. Component App renders component Greet.
  4. ReactDOM renders App 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!

Top comments (0)