NOTE: This post is a chapter from my React book that appears near the beginning of the book. It is a work in progress as I continue to finish the book.  You can follow along with book progress here.

React is A User Interface Library

Out of the box, React is a library for building user interfaces.

Although React is a JavaScript library, the interfaces React builds are agnostic.

Several React companion libraries exist in order to make the interfaces you build work in the browser, on the server, in native applications and even in 360 and VR environments. In this book we focus on working with ReactDOM, the library that manages adding the interfaces we build with React to client side web sites and applications.  ReactDomServer, ReactNative and React360 are also libraries you may want to explore for using React interfaces in other environments.

In addition to providing helper functions for building interfaces, React’s architecture allows for you to handle interactions with your interfaces, whether that involves event handling, api calls, state management, updates to the interface, or more complex interactions.

React does not provide as many helper functions as some JavaScript frameworks. This is in large part why we call React a library and not a framework. You will still need to write plenty of vanilla JavaScript when working with React.

React Uses Component Architecture

A component is an independent, reusable piece of code (created via a function or class).

React uses a component architecture for building user interfaces and organizing code. The main file for a simple React app may look something like this.

// Import React and Other Components
import React from 'react';
import { render } from 'react-dom';
import Header from './Header';
import MainContent from './MainContent';
import Footer from './Footer';

function App(){
  return (
    <div className="app">
      <Header />
      <MainContent />
      <Footer />
    </div>
 );
}

ReactDOM.render( <App />, document.getElementById("root"));

We can see here a few components in use. <Header />, <MainContent /> and <Footer /> are all components. The App() function is a component as well and we can see on the last line of this example how we can use the ReactDOM library and the ReactDOM.render() method to manage adding the UI we build to a webpage.

If we dig inside of the <Header />, <MainContent /> and <Footer /> components, we would likely see the use of more components as well as what looks like HTML markup.

import React from "react";
import Ad from "../Ad";
import logo from "../assets/logo.svg";

export default function Header() {
  return (
    <header className="app-header">
      <Ad />
      <img src={logo} className="app-logo" alt="logo" />
      <h1 className="app-title">Site Name</h1>
    </header>
  );
}

In this <Header /> component above we can see that we are pulling in yet another component called <Ad />. Most React applications contain several layers of component nesting like we see with <App />, <Header /> and <Ad />.

We also see the use of HTML elements in our React code.  This is possible thanks to a library called JSX, which lets you write “HTML markup” directly in your JavaScript.  Since we are using React to create user interfaces, and user interfaces on the web involve HTML markup, this makes sense we would see HTML like elements within our UI components.  We will explore JSX in depth in this book.

If we look at some code from for a simple React app built using React 360, React’s VR library, the actual components we call would be different, but the component architecture is still present.

import React from 'react';
import {
  Text,
  View,
  VrButton,
} from 'react-360';

class Slideshow extends React.Component {
  // Code removed for brevity
  return (
    <View style={styles.wrapper}>
      <View style={styles.controls}>
        <VrButton onClick={this.prevPhoto}>
          <Text>{'Previous'}</Text>
        </VrButton>
        <VrButton onClick={this.nextPhoto}>
         <Text>{'Next'}</Text>
        </VrButton>
      <View>
        <Text style={styles.title}>{current.title}</Text>
      </View>
    </View>
  );
}

The code above creates several layers of 360 views with some buttons and text overlaid. While the actual code might not make complete sense, it should be clear that we have several nested components representing view, buttons and text.

This is a good example because you can see how the same components are reused in different ways by passing them different parameters, or what React calls props.  Understanding how data passes through React components is important for understanding the typical component architecture used for building with React.

React Has A One Way Flow of Data

React follows a convention of getting and setting data at the highest point necessary in a component hierarchy for data to pass in a one way direction down through an application.Let’s take a look at this example and imagine some of the types of data we would need for various components.

function App() {
  return(
    <React.Fragment>
      <Header />
      <Content />
      <Sidebar />
      <Footer />
    </React.Fragment>
  );
}

Something like the name of the site might need to be available to both the <Header /> and <Footer />. The main content for the particular page would need to be passed to <Content />. Some additional widget data might need to go to <Sidebar />.

function App() {
  const siteTitle = getSiteTitle();
  const widgets = getWidgets();
  const mainContent = getPageContent();
  return(
    <React.Fragment>
      <Header siteTitle={siteTitle} />
      <Content mainContent={mainContent} />
      <Sidebar widgets={widgets} />
      <Footer siteTitle={siteTitle} />
    </React.Fragment>
  );
}

This convention of making up attribute names and assigning them a value is how we pass data into a component.

Now the <Header /> and <Footer /> have access to the siteTitle, the <Content /> has access to the mainContent, and <Sidebar /> has access to the widgets it needs.

An important note is that this pattern of passing data into a component only passes the data one level. Components inside of <Header /> will not automatically get access to siteTitle.

function Header(props) {
  return(
    <header>
      <p>We can see the {props.siteTitle} here.</p>
      <PageHeader siteTitle={props.siteTitle} />
      <PageSubHeader />
    </header>
  );
}

You can see here that inside <Header /> we can call props.siteTitle and have access to that value we passed into it. However, if we wanted to have access to siteTitle within the <PageHeader /> component we would have to manually pass that information down as well.

 

When a component receives a value as a prop, it should not modify it.  Props should pass through a component tree as immutable data.  This ensures that any component that references a prop, references the same value as it’s parent of children components.

The value of a prop should only be changed in the component that originally set the value of the prop and started passing it down through the component tree.  In our example code above, the <App /> component could change the value of siteTitle, but the <Header /> or <PageHeader /> components should not.

To understand the flow of how dynamic data gets updated in a React app involves discussion of state and how event handlers can be passed as props.

React Components Can Have State

As we have learned, data flows down unchanged through components as props.  Data is set at the highest component in the tree necessary for all children components to be passed the information need as props.

In some cases, this data is received once and does not need to change.  In many cases though that data must remain dynamic and have the ability to update at any given time and have that update be reflected in all children components.

To keep track of data that changes in React we have a React state object and a set of helper functions to update the state value.

Here is an example of a counter that would update itself.  The value of the counter is a value that is dynamic within this component and therefore makes a good instance of when to rely on state.  Note that to make components with state, we must use JavaScript classes rather than functions.

class Counter extends Component {
  state= {
    counter:0
  };

  handleCount = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  render() {
    return (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleCount}>Count Up!!</button>
      </div>
    );
  }
}

Now it is important to note that this state is scoped to just this component.  The value of state in counter would not be available to child or parent components.

So in a more complex example example, like below, we would have to pass the value of counter down as a prop into the child element.

class Counter extends Component {
  state= {
    count:0
  };

  handleCount = () => {
    this.setState({
      count: this.state.count + 1
    });
  };

  render() {
    return (
      <div>
        <PageHeader count={this.state.count} />
        <button onClick={this.handleCount}>Count Up!!</button>
      </div>
    );
  }
}

The <PageHeader /> count prop gets updated every time we update the state in the <Counter /> component

function PageHeader(props) {
  return <h1>{props.count}</h1>; 
}

The nice thing about this approach is that anytime state is updated, a new value will be automatically passed down into any child components with the value of a prop set to state.

This allows us to have a single point of truth for dynamic data.  The source of truth is the value in state, managed from a single component.  All instances of this value in children components are immutable values received as props that should not be changed outside of this component.

Components that appear above this component in the hierarchy would not have access to this data as it is only passed down via props.  We see again why we try to set and manage state from components higher in the hierarchy so that the data is available to everything that needs it.

There are some other architecture patterns, like higher order components and the context API, which circumvent needing to manually pass tons of props through your app.  We will explore these in more depth later.  For now we want to make sure we understand this high level overview of how things generally work before we start taking shortcuts.

Updating Component State from Child Components

Now, what happens when we want to trigger state to be updated from a child component?

Imagine, for instance, that with the example above we wanted to have a <Button /> component rather than a hard coded button in our main <Counter /> component?  This is actually quite common in complex apps.

The solution to this, in the React world, is to pass the event handler function that updates the state with setState down as a prop.  Then it can be called from any child component, but the action will take place in the original component that set the state and has the ability to update it as well.  Other patterns for this exist, but this approach is the most basic.

If you are not familiar with passing functions as parameters, it is completely valid vanilla JavaScript.

Once state is updated, it will be passed down through the component hierarchy via the props.

Here is an example of what that would look like.

class Counter extends Component {
  state= {
    count:0
  };

  handleCount = () => {
    this.setState({
      count: this.state.count + 1
    });
  };

  render() {
    return (
      <div>
        <PageHeader count={this.state.count} />
        <Button handleCount={this.handleCount} />        
      </div>
    );
  }
}

function PageHeader( props ) { 
  return( 
    <h1>{props.count}</h1>
 ); 
}

function Button( props ) {
  return(
    <button onClick={props.handleCount}>Count Up!!</button>  
  );
}

Here we can see a simple example of how React handles data flow.  There is a single point of truth for data.  That exists in state set and updated from a single component.  Data is passed in a one way flow down through a nested component tree via props.

If state needs to be updated from a component other than where it was originally set, then an event handler can be passed down to the necessary child component as a prop.  This keeps data immutable and flowing one way because even if a child component triggers a change, that change takes place higher up in the original component.

When we assign the value of a prop to something from state, like below, that prop value will automatically update whenever state changes.

<PageHeader counter={this.state.count} />

Any other child component that references that prop value will also receive the update automatically.  This is the beauty of data flow in React.

This can take a little while to get used to depending on how you have approached problems like these with JavaScript in the past.  However, this should all serve as a good starting point for us to be able to dig deeper into explaining React.

Getting Ready to React

From here in the book we will begin looking at the default React object that contains the core React library.  We will break down the major sections, focusing on what the major helper functions do and when we would use them.

We then proceed into more depth on the concepts we outlined above, learning how to put them into practice with real world applications as we go.  Of course, there is more to React, and we will go beyond what we have outlined here in this chapter as well!

As this post is a work in progress, please let me know your thoughts (and corrections)!