Essential Terms for a React Developer

Ho-Wan
Level Up Coding
Published in
11 min readDec 20, 2019

--

This article is an overview of React for software development. It presents essential terms and concepts for anyone that is looking to work with React or to learn more about it. I started using React.js just over a year ago and built Spandraw using it. This article covers the most important things I learned in the process.

If you are looking for an overview of modern web development terms, you may find my previous article on web dev useful. It provides an explanation of what React is and why it is used.

JSX (JavaScript XML)

JSX files represent JavaScript files that include XML syntax (like HTML). When using React, all the components should be written in JSX syntax. JSX makes it possible to combine HTML, JS, and CSS together into a component, often as an individual file, and this is one of the main purposes for React.

DOM (Document Object Model)

The DOM in the interface that represents HTML elements on a webpage. For example, each paragraph in the article may be represented inside a <p /> element, whereas an image would be inside an <img /> element.

React has its own representation of these elements on the web page. This is referred to as the React DOM, and this concept is called the virtual DOM. Other front-end frameworks such as Angular and Vue uses a similar virtual DOM principle to manipulate the HTML on the web page.

SPA (Single Page App)

A Single Page App is a single web page that changes its own content when navigating to sub-domains within the URL, instead of loading a different web page from a web server. This is because JavaScript is able to change the HTML on the page in response to user actions.

Entrypoint

The entry point is the base URL where the app is hosted. Using my own app as an example at app.spandraw.com, this would be the entrypoint, and this location would contain an index.html file in the root directory. This index.html only needs to contain a single <div id=”root” /> element, along with appropriate headers. The JavaScript for the whole ‘app’ is loaded, then can target this div element and replace with the necessary content. Often, the root component is called “index.jsx”.

Router

When the user navigates to the page app.spandraw.com/draw inside a react app, the index.html at app.spandraw.com is still loaded. The sub-url ‘/draw’ is recognized by the client-side router, the desired components are rendered inside of the root div element.

Changing pages inside the same app means that the same components can be used, and data can be shared between different pages inside this app as a ‘state’.

<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/draw" component={Draw} />
</Switch>

Lifecycle methods

Lifecycle methods are functions that get called at specific scenarios inside a React class component. These are only available in the Class components, not the function components using Hooks. The most common lifecycle methods are componentDidMount(), render(), and componentDidUpdate().

componentDidMount()

componentDidMount() is called when the component is created. This is useful for carrying out actions that only need to be done once when the page is loaded, eg. checking if the user is logged in.

render()

render() is called every time the component updates, including when created. React works by only updating components when the ‘state’ or ‘props’ of the component changes. Any text and HTML elements that need to be shown needs to be returned from this method, using JSX syntax.

Example from official React docs:

render() {
return <h1>Hello, {this.props.name}</h1>
}

componentDidUpdate(prevProps, prevState)

componentDidUpdate() is called every time the component updates, but not when a component is created. Render() only has access to the current state and props, whereas componentDidUpdate() has access to the previous state and props as well.

When render() is called, you know something has changed but you do not know what. In componentDidUpdate(), you can check specifically what has changed, and carry out the logic for that condition only.

Example from official React docs:

componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}

React Components

One of the main purposes of React is to reuse code, by grouping the code into a ‘component’ that corresponds to an element to be rendered to the page. There are two main types of components, a ‘Class’ component (the standard React component), or a ‘Function’ component.

The Class component has lifecycle methods (ComponentDidMount, ComponentDidUpdate, etc, see above) built in. The Function component is a standard JavaScript function and uses React Hooks to access state and react lifecycle functionality without using a class.

Props

Props are used to pass data between connected components (parent to child or vice versa). The convention in react is to pass the data in an object called “props”. For a class component, this can be accessed in the lifecycle methods using “this.props”. For a function component, the object “props” is passed in as a parameter to the function.

When any of the props being passed to the component change, the component will update (re-render), so any relevant lifecycle methods will be called, such as render() and componentDidUpdate(), and so on.

State

State is used within a component to hold data that changes but does not need to be exposed to other components. The main difference between props and state is that the component is able to update its own state, but props can only be changed when passed in. In class components, state is changed by calling this.setstate({…}). In function components, state is changed by using useState Hook from React.

As with props, if any of the state changes, the component will update and call the relevant React lifecycle methods.

Pure Component

Using React.PureComponent is similar to the familiar React.Component except that PureComponent implements a “shallow prop and state comparison in shouldComponentUpdate()”. Using “Component” expects the user to perform the shouldComponentUpdate() manually to optimize updating if and when necessary. What this means in practice is that React automatically implements something like this for all the props and state in the PureComponent:

shouldComponentUpdate(nextProps, nextState) {
// update component if any of the props or state is changed using a shallow comparison
If (this.props.isLoading !== nextProps.isLoading) return true;
If (this.state.isButtonClicked !== nextState.isButtonClicked) return true;

// otherwise do not update component
return false;
}

For the majority of components, PureComponent is generally more performant than Component as it avoids unnecessary updates unless relevant props or state has changed.

However, where more complex data is being used and it is necessary to check if an item reference (and not just the value) has changed, then “Component” should be used. When the component contains an object or array in props or state, then you should consider whether a shallow comparison is acceptable or not. The risk of using PureComponent is that the component does not update when expected.

Event binding

One particularly confusing area as a React beginner is how to bind event handlers in React. There are three types of data you may wish to pass to a function to do event handling, which are:

  1. Access to props or state on the React component
  2. The ‘Event’ itself (often click, keypress, or form values)
  3. Any other custom values

It was confusing to me because there are so many ways to do this, especially given the power of the arrow function since ES6, and different people do it in different ways. However, abusing the arrow function can lead to poor readability of code and trigger unnecessary renders, hurting performance.

My personal approach is:

handleClick() {
console.log(‘handleClick does not need to be an arrow function’)
}

render() {
return <SomeButton onClick={this.handleClick} />
}

If you forget to bind ‘this’ to the component to pass to the method, you will get an error along the lines of `Cannot read property ‘props’ of undefined` — because ‘this’ is undefined. When you get this error, the first thing to check is that you have bound ‘this’ for your event handling methods.

constructor(props) {
super(props);
this.handleGetDataFromProps = this.handleGetDataFromProps.bind(this);
}

handleGetDataFromProps() {
const { data } = this.props;
console.log(‘handleGetDataFromProps has access to data from component props: ’, data)
}

render() {
return <SomeButton onClick={this.handleGetDataFromProps} />
}

In case 3, inside the event handling method, it would be usual to do setState or triggering a redux action based on the input values.

The airbnb react style guide on github is a good source of reference for good practices when using modern javascript with React.

React Hooks

React Hooks were introduced in v16.8 (Feb 2019). The description from the React documentation is ‘They let you use state and other React features without writing a class’. Here is an example (taken from react docs):

const [count, setCount] = useState(0);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});

Hooks and classes work in fundamentally different ways, the following may help you decide which to use:

  • Classes work through lifecycle events.
  • Hooks work through synchronization.

As of currently (Dec 2019), react hooks are still relatively new, so there are less documentation and articles out there compared to class components. If you have the time, then by all means, experiment with hooks and read the documentation. From what I’ve read, hooks can do anything that classes can, except for the ComponentDidCatch lifecycle event.

Redux

When creating a React application, it is likely that you will need to share state between components. One way to do this is to pass the state into a child component as a prop. However, this gets messy quickly when introducing more states to pass and more layers of components. Then there is the issue of keeping track where the state is being changed, and trying to track down which component is mutating the state, which also gets messy quickly in a complex application.

Redux(link) is a library that adopts best practices for managing all these states, adopting the “Flux” architecture created by Facebook. It does this through three main principles:

  1. Using a central ‘store’ to save all ‘states’ (sometimes referred to as the Redux Store).
  2. All ‘states’ in the Redux Store is read-only. To change any state in the store, a Redux Action must be dispatched.
  3. To change the Redux Store, a ‘reducer’ is used to look for the type of action, and change the state accordingly. It is recommended to return a new state instead of mutating the previous state (ie. Pure Function), and this is particularly important when using arrays and objects.

Using Redux

This store can be accessed from any component, by using ‘mapStateToProps’ and ‘mapDispatchToProps’, and wrapping the component in ‘connect’. Actions are passed in as a function prop through mapDispatchToProps. The use of a ‘Selector’ function is optional, however I would recommend it because if you wish to rename a state or nesting in the store, you can change just the selector function instead of going to every component where this state is used and changing mapStateToProps there. For complex apps, it is recommended to divide the Redux store into multiple parts corresponding to their purpose, each with its own reducer.

One of the main benefits of using Redux is the power of devtools plugin for Chrome. It allows you to see all the states in the Redux Store, any action that is triggered, and how the store changes in response to the action (ie. to check the reducer is doing its job). In my opinion, if you need to build a React app that needs to scale, then you need Redux.

Redux Saga

If you are using Redux and you need to use asynchronous actions (ie.fetching an API, chaining actions), you will want to use some type of middleware to handle this. Redux Saga is a middleware that can intercept a Redux Action and carry out logic asynchronously based on the outcome of the API call. I personally use Redux Saga and have found it to be incredibly useful, but there are alternatives depending on the scope of the use case.

As an example, you can use Sagas to listen for a ‘Get API’ action, then call the REST API, listen for the response. If you get a status 200 response, return a ‘API success’ action, and if you get a status 400, return a ‘API failed’ action. This action can then be picked up by the reducer, and the state can be changed accordingly. This is a good way to set a ‘loading’ state to render a spinner when waiting for the response from an API request.

TypeScript

TypeScript is basically JavaScript with type definitions. TypeScript files end in *.ts (or *.tsx if replacing a *.jsx file), and this gets automatically compiled into JavaScript files which can be run in a web browser. It is created by Microsoft and works particularly well with the VS Code editor, which was written with TypeScript.

Pros:

  • Catches errors due to incorrect types inside your code editor, instead of at runtime.
  • Assists with code completion (Intellisense) and editor tools like “jump to definition”, saving developers a lot of time
  • It helps teams communicate code base and structure the application
  • Helps to document libraries — almost every major npm package has typescript definitions

Cons:

  • More verbose, need to type more
  • Compile errors can block the app from running, can be frustrating when prototyping new features and just need to log some results
  • Not as easy to copy & paste from other places

In my opinion, the benefits of TypeScript far outweigh the cons, and I wouldn’t consider building a new React app without it. When building my own app Spandraw, I started off by using only jsDoc, which was ok for a small app, but quickly ran into issues when scaling. Then I switched to TypeScript, gradually learning the ins and out of it. The more I use it, the more valuable it feels, and that can only be a good sign.

TypeScript in 2019 is a lot better than 2017/2018, and React community has really embraced it. If you are building an app that needs to scale and has more than a handful of components, then you really should be looking to use TypeScript along with Redux.

Styled Components

Styled Components is a library for writing CSS components in JavaScript, also called CSS-in-JS. This allows the use of variables, which can be passed into the ‘styled component’ as a prop or directly imported as a constant. Styled Components can be included in the same file as the React component itself, which is my preferred style. This avoids having to switch between the React and CSS file during development.

One advantage over inline css is that it uses the same syntax as CSS, whereas using React’s inline-css requires CSS into a JS object. This requires converting dashes in names to camel case and values to strings, and it is easy to make mistakes when doing this conversion.

There are many ways to implement CSS in React apps, as the default CSS has limitations with using variables. Some of the other approaches include SCSS, LESS, CSS modules. I personally recommend Styled Components with React as they compliment each other well.

If you found this overview of React useful, connect with me on LinkedIn or follow me on Medium. I used to be a structural engineer and I plan to write about that along with computation. Check out the progress of my own React App at Spandraw.com

Originally published at https://spandraw.com on December 20, 2019.

--

--