Helpful principles when starting with React

Design the React way

It always pays off spending time analyzing mockups in favor of building better architectures. In React’s case, this phase would mean turning your UI’s into a top-down tree of components, by delineating each UI section based on a particular functionality. Consolidating reusable pieces that could potentially be shared across the app, and listing all the possible states each of these components may have. All these are things we have to consider in order to get the most out of the React, so it’s important to understand the philosophy of the library, and how our app can benefit from this mentality.

componetize

A component can be seen as a part of the UI that performs a particular function, or a building block for larger structure

 

Stateless components don’t carry heavy luggage

Clearly define which components should be containers and which ones should be presentational (See smart vs dumb). Not making a clear distinction early in the design phase can make for a complex relationship between your components, and the data they share.

Stateless components are predictable. They only have one data entry point and it’s fulfilled by a parent component in the shape of a props object. This makes their behavior lighter and easier to share across the app (think of top-down flow). For these same reasons props should be your friends. And you should try to use them as much as possible when you need to update state.

Though, in some cases sub-components need to save their UI state somewhere. A group on-off buttons, or select-items in a dropdown could benefit from a parent (smart) component to manage their state. This way you wouldn’t have to keep track of each the sub-component’s state separately, and writing tests wouldn’t be as tedious since you’re not writing extra logic just to recreate all of the separate UI cases.

smart components vs dumb components

Component state is for UI

It’s recommended to use the component’s state only to represent its most pure form of UI, and not variations of it. For example, if you want to show sorted list of items, just store the basic list and sort the list under the render method. Remember that React is a view rendering library, and keeping track of unnecessary data in your state can give your component too many responsibilities. To solve more complex app state concerns, use something like redux, flux, or mobX.

state and dom

Optimize by understanding the component’s lifecycle

When a component is rendered, React tries to optimize in a way that only the altered state gets modified in the DOM (see virtual DOM). But this doesn’t mean the work is over. You still need to care about how often your render method will be called. Updating the state will always trigger a re-render, and you can prevent unnecessary render calls by adding conditional rendering logic inside of shouldComponentUpdate(). This method is one of several hooks React provides to intercept events that happen in a component’s lifecycle. Knowing these hooks is vital to understanding React, and can help you make better decisions when structuring your component’s logic.

Understanding the lifecycle can help:

  • Optimize the rendering process
  • Know where to fetch external data and avoid race conditions
  • Update the state at the right time
  • Take action upon receiving new data from a parent component
  • Execute code after an update
  • Know when to dispose of a component
  • Initialize a container component with state

lifecycle

Benefit from immutability

Immutability is not particular to React. It’s a common pattern of functional programming languages like haskell, clojure, elm, etc. But React is no stranger to these patterns since its heavily based on the composition of functions, and concepts like stateless components (pure functions). Once an immutable object is created, it can no longer be altered. This means that if a series of functions operate over an object independently, the end state of the object would be the same as when it was created. This can help building more predictable and debuggable architectures.

Mutable objects are hard to monitor. If an object touching several parts of a system creates a bug, it’s really hard to know in which part of the system this happened, or which function mutated this object and ignited this bug. For this same reason we usually tend to create copies of object to avoid reference conflicts. This is where an immutable library can help us handle all of the object manipulation and copying automatically.

A few benefits of immutable objects:

  • Applications make more sense from beginning to end since values are more predictable
  • Easier to debug, since you have a better sense of where your data is created
  • Easier to cache, since data won’t change
  • Safe parallel execution, since different parts of your application can operate on the same data location without conflicting with each other
  • Avoiding deep equality checks, since new values are new copies
  • Reduce the number of null references

  • On the downside, if objects are too big, memory usage can be a problem since objects are being cloned.

immutable objects

React doesn’t enforce immutability out of the box, but you can achieve it by using their own provided ‘react-addons-update’ module, or the more popular immutable.js library, which has tons of features to operate on all types of things, like maps, lists, arrays, stacks, and also provides ways to deal with performance.

Use pure React until you can’t

When starting out, I think its key not to get too distracted by the large amounts of React boilerplates out there. These repos often include complex architectures and/or plugins that you might not need when starting out, and can definitely confuse you early on.

Try to build your application using pure React until you hit its limits. This will kinda force you to explore its features and understand the core concepts better. Starting out with extra layers of complexity can slow your flow and kill your motivation. Go as far as you can without using extra plugins and when you find yourself hitting a wall, you’ll organically find yourself looking for plugins and middleware to solve additional concerns related to things like state or scalability.

Share