Thinking in React

Published Jun 05, 2017Last updated Dec 01, 2017
Thinking in React

React is different in so many ways from its front-end predecessors! So much so that it triggered a renaissance in front-end and UI development in general. See Preact, Inferno, Rax to name just a few. Besides that, it also went into native UI development with React Native and now to user interfaces in VR with React VR.

React is becoming more of a standard rendering target for various platforms - web, mobile native, OS native and others. People are targeting React and adopting it in multiple platforms - a good example of this is React SketchApp, which allows React components to show up in Sketch. We've just scratched the surface of what's possible with React and the opportunities that it brings for UI development in general.

It's not about the React library

It's about the React way of thinking. We’ve gotten used to showing a user interface then mutating it to update and show the latest changes. What React did very well was to bring immutable UIs to the masses - you never "mutate" a UI - you always (re-)render it! Always run the same function that was used for the initial rendering to get the updated interface. This leads us to the main point of the React way of thinking.

It's not about React - the library. It's about the React way of thinking.

It's about declarative UIs

The main point of React is that it frees you from having to think how you transition your UI from state A to state B. This might not look like a big deal, but once you also have state C and state D and state E and so on, and have to explicitly program how you transition from A to all those states, then you begin to realise the power of React’s declarative way of describing UIs (and how difficult imperative UIs are to maintain).

Let’s look at a quick example with vanilla JS and then with React. Say we have an email input; when there is no value it should show a warning, when there is an invalid email it should show an error, and when it contains a valid email address it should hide all messages.

var emailInput = document.querySelector('.email input');
var messageDiv = document.querySelector('.email message');

emailInput.addEventListener('change', function(e){
  var value = e.target.value;
  var valid = isEmail(value);
  if (valid){
    messageDiv.removeClass('invalid');
    messageDiv.removeClass('warning');
    messageDiv.addClass('valid');
  }
  // ... handle is empty 
  // ...
})

This already looks complicated. While in React, all we do is

class extends React.Component {
  render(){
    return <div className="email">
      <input onChange={e => this.onChange(e)} />
      <div className={this.state.cls} />
    </div>
  }
  onChange(e) {
    const value = e.targe.value;
    this.setState({
      cls: isEmail(value)?
             'valid':
             value ?
               'invalid':
               'warning'
    })
  }
}

State evolving over time is the root of most UI bugs, and this is where React really shines. It frees the developer from having to think about state transitions. Conceptually your UI is being re-rendered from scratch, so there is no need to do the mutations by hand.

Conceptually, you can think of React as re-rendering the whole UI from scratch - on every change.

Small API surface

With the above example we've covered most of the React public APIs. The beauty of it all is how small of an API React introduces - it's almost too simple to be true. Yet the render method, the component props, and the component state are the most important things in a React app - getting a good grasp on these paves the way for productively using React in commercial apps.

In my 10+ years of experience, I've never found another way to write UIs so quickly and powerfully.

Of course tech is evolving naturally and getting better over time, but the jump that React has proposed is a huge leap forward. Most of the ideas are not new, they have been around for quite a while - but React has successfully managed to bring those very good ideas into a coherent library with a clear API and a small, focused purpose in mind: only build user interfaces. No data fetching, no user models, no forced app structure, etc. Although all those things have their place in UI development and are valuable, React wanted to do only one thing really well: build UIs. That's it.

React was written with only a single purpose in mind: describe & build UIs as naturally as possible.

On component props and state

Component props & component state are basic concepts in React:

  • the props of a component are passed into the component by the owner component. Component props should be treated as immutable, so they should be used as read-only by the component itself.
  • component state is stored internally in the component, and is only managed by the component itself. As a best practice, it's also good if you treat component state as immutable (although it isn't), and whenever you need to update the state, make sure you provide a new reference for each property in the state.
class ContactInfo extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      address: {
        city: 'New York',
        street: 'Chrown Str'
      }
    }
  }
  onStreetChange(city) {
    this.setState({
      address: { city, street: this.state.street }
    })
  }   
  onStreetChange(street) {
    this.setState({
      address: { street, city: this.state.city }
    })
  }
  render() {
    return <div>
      <h2>{this.props.contactName}</h2>
      <input
    	onChange={(e) => this.onCityChange(e.target.value)}
       value={this.state.address.city}
      />
      <input
    	onChange={(e) => this.onStreetChange(e.target.value)}
       value={this.state.address.street}
      />
   </div>
 }
}

const App = (props) => {
 return <div>
   {/*
     The ContactInfo components receives a props
     object like { contactName: "Richard" }
    */}
   <ContactInfo contactName="Richard">
 </div>
}

ReactDOM.render(
 <App />,
 document.querySelector('#main')
)

In the above example, notice how state is updated with a new address object on every change - this avoids skipping updates when React.PureComponent is used - which is just a React component that only re-renders when it receives new values for props and for state (it shallowly compares the old and new props objects and the old and new state objects).

In addition, React supports functional components, which cannot have state, and are called with the corresponding props object.

Understanding props and state is crucial for being productive with React.

Controlled components

Another powerful concept in React apps is controlled props - it basically means components don't store any intermediate state for the controlled props (for example on updating the value inside a text input), but rather on every change, they notify the owner component of the change, so the owner can re-render the controlled component with updated values for the props.

// controlled input
<input value={this.props.value} onChange={this.props.onChange} />

// uncontrolled input
<input defaultValue={"initial value"} onChange={this.props.onChange} />

The above inputs are example of controlled components (already baked into React), but basically this is the gist: uncontrolled components use their internal state to update their UI, while controlled components always show values from props. As a result, when owner components decide not to re-render a controlled component, even though the user may interact with the component (for example, a text input), nothing will happen and there will be no change in the UI.

Universal platform

Once you get a grasp of React and the React way of thinking about UIs, you'll suddenly realize all this knowledge can be applied to UIs everywhere, not just on the web. And the beauty of it is that in almost no time you can become productive in building native UIs for mobile or desktop operating systems, or even for the webVR now that React is becoming widely adopted, with libraries written to target multiple platforms, but with one common way of thinking about UIs - declarative and component-based.

While the old Java slogan "Write once, run everywhere" is not fit for user-interface apps written in Java, React's new approach of "Learn once, write anywhere" is really productive and life-changing.

React offers true "Learn once, write anywhere"!

I'd love to hear how you picked up React! How long did it take for you to become familiar with it? What about productivity once you grasped it?

Discover and read more posts from Radu Brehar
get started
Enjoy this post?

Leave a like and comment for Radu

19
20