Clean code is a consistent style of programming that makes your code easier to write, read, and maintain. Below I'll give you hints on how to structure and format React code, will describe how different components can be written, will explain the differences between class-based and functional components.

React is just a view library

Let's get the basics out of the way. It's just a library for rendering your views. If you're coming from the MVC world, you need to realise that React is just the V. Probably one of the main goals of React is manipulation of VirtualDOM to speed up real DOM. React was designed so to make changes to your DOM when it's actually needed. That's the main reason do not make any changes to the DOM outside of React, neither through native JavaScript nor through other libraries like jQuery (Do not use it with React, that's very bad practice).


Code style

Let's start with the simplest - how you style and format your code? To avoid writing code in a different code style (which further complicate the work of the entire team), you should decide which rules to follow for formatting your code. The most popular is Airbnb React/JSX Style Guide and I personally recommend you to follow this guide, as it describes a pretty well-styled way to write code and most of the developers already use it in projects.


Naming should be descriptive

Most of these things are self-evident (and even described in the documentation), but nevertheless, many programmers do not pay attention to them.

  • Use .jsx extension for React components.
  • Use PascalCase for filenames (e.g. AcmeComponent.jsx).
  • Use the filename as the component name.
  • React events are named using camelCase (also custom event props), and starts with on... (e.g., onRedButtonClick).
  • Event handlers should start with handle... (e.g., handleRedButtonClicked).
  • Variables (or constants) which contains boolean value should start with is... or with has... (e.g., isLoggedIn and not loggedIn; hasChildren and not children).
  • Do not name your methods with underscore prefixes for properties and methods.

Just an addition I would like to add, that better use almost always (99%) const instead of let. If you assign to object (yes, just a reminder, in JavaScript everything is an object) completely another value, would be more clear to assign this value to separate variable. If you just modify the value of an object, const should be enough, as a reference to this object did not change. Your data should be immutable as much as possible and let can be used for iterator in a loop.


Put state as high up as possible

If a component has state, nothing above it in the tree of components should care about that state. This means that most of your state should live in your top-level component (or inside your flux store if you use some sort of flux library). There are cases where the state might be kept in components, not at the top level, but the state should be entirely internal.

Note, that you should split up the usage of props and state. If you have the state that needs to get updated when props change then that is clearly not state internal to this component. The state should live further up in the component tree (and it apparently already does to some degree since it keeps getting reset from props).

Passing setState a function

Here's the dirty secret about setState — it's actually asynchronous. React batches state changes for performance reasons, so the state may not change immediately after setState is called.

That means you should not rely on the current state when calling setState — since you can't be sure what that state will be!

The solution is to pass a function to setState with the previous state as an argument:

    this.setState(prevState => ({ expanded: !prevState.expanded }));

Keep your components small

This might seem like an obvious one, but it's worth calling out. Every good developer knows that small classes/modules/whatever are easier to understand, test, and maintain, and the same is true of React components. Making each of your components smaller leads to easier reuse and easier understanding. If you split your code into multiple smaller files and each file contains only one logic, then it becomes very easy for the reviewer to review that file. Remember, only one level of abstraction per component.

Only render should return components

JSX components should be returned only in render(). If you have inside your component other methods which return components (e.g., renderStepOne(), renderStepTwo() etc.), you should split them up to separate React.Components.


Split your code into multiple smaller functions

Splitting your bigger functions into multiple smaller functions will make the smaller functions more reusable. They will also become much easier to test.

You can also create many utility files which can help you remove the duplicate code from multiple files.

After creating multiple files, look at them and you will see that there are many duplicated lines of code. You can take these lines are create a utility file. You can then reuse the same utility file across multiple files.

The one level of abstraction rule gives other developers, who read your code an option to ignore implementation details if he/she does not care. Overall, the logic is much more explicit, making the code less error-prone. After refactoring, some bugs become pretty obvious. So remember, only one level of abstraction per function.


Use classnames package

classnames is a great package to generate component class names. In practice, there are many cases when different classes should be applied to the component. To avoid conditions in your code, which are almost always is very messy, you can prepare class names using this package. It's very easy to use, just let package knows in which cases which classes should be added.

    const btnClass = classNames('btn', {
      'btn-pressed': isPressed,
      'btn-over': !isPressed && isHovered
    });
    return <button className={ btnClass }>{ label }</button>;

Destructure when applicable

ES6 introduced the concept of destructuring, which really is your best friend. Destructuring allows you to “pull apart” properties of an object or elements of an array.

Most of the time you'll need to destructure props and state to use constants in your component:

    const { title, attributes } = this.props;
    const { isLoggedIn } = this.state;

An often overlooked ES6 feature is array destructuring. Take the following code for example.

    Object.entries(obj).map(entry => {
        const [key, value] = entry;

        // Processing ...
    });

Destructuring array is a much more clean way to access array item, as trying to get them by key.


Use stateless functional components

Stateless functional components (SFCs) were introduced in React v0.14.0, and they are used to greatly simplify a render-only component. But some developers haven’t let go of the past. These components have no state and no methods. They’re pure and easy to reason about. Use them as often as possible.

const HoverLoader = () => (
    <div className="hover-loader">
        <div className="auto-spinner blue" />
    </div>
);

export default HoverLoader;

This is by far my favourite method for defining React components. Apart from the more concise syntax, this approach can really help make it obvious when a component needs to be split up.

It's important to note that functional components have a few 'limitations', which I consider to be their greatest strengths. The first is that you may not use the ref attribute on functional components because they don’t have instances. refs encourage a very imperative, almost jQuery-like way of writing components, taking us away from the functional, one-way data flow philosophy for which we chose React in the first place!

The other big difference is that functional components cannot have state attached to them, which is also can be a huge advantage, as it's much easier to test.

Note: ES6 feature, which a lot of developers don't want to understand, that {} return nothing by default, but [] and () return its content by default.

Note: If you are using refs in your code, create them as React requires them to be created: this.myRef = React.createRef();Read more....


Conditionals in JSX

Nested ternaries are usually not a good idea. Use curly braces wrapping an IIFE, and then put your if statements inside, returning whatever you want to render. Note that IIFE’s like this can cause a performance hit, but in most cases, it will not be significant enough to warrant losing the readability factor.

<div>
    {
        (() => {
            if (isLoggedIn) {
                return <GreatingsUser />;
            } else if (hasEmail) {
                return <GreatingsEmail />;
            } else {
                return <GreatingsGuest />;
            }
        })()
    }
</div>

Splitting up your components as much as possible is always a good call. But keep the IIFE approach in mind as a fallback for quick conditionals.

Booleans, Null, and Undefined Are Ignored

false, null, undefined, and true are valid children. They simply don't render. This can be useful to conditionally render React elements.

<div>
    {
        messages.length > 0 &&
        <MessageList messages={messages} />
    }
</div>

Use propTypes and defaultProps

propTypes and defaultProps are static properties, declared as high as possible within the component code. They should be immediately visible to other developers reading the file, since they serve as documentation.

All your components should have propTypes (as soon as the component has props)

propTypes will help you check if the desired type of prop is getting passed into your component or not. If the proper type of a specific prop is not passed into your component, then the package will throw a warning in the console of your browser.

All properties which are not required must have defaultProps.

To avoid reassigning props inside of component and be aware all your props is set, you need to define them as defaultProps. This object will be merged with props you set while initializing component.

Define them outside the component

As propTypes and defaultProps are static properties you can define them dynamically outside the class. This will help make your component more compact and their definition will be identical for both class-based and functional components.

export default class RatingStars extends React.Component {
    // Logic goes here
}

RatingStars.defaultProps = {
    enlarged: true,
    isSelectable: false
};

RatingStars.propTypes = {
    count: PropTypes.number.isRequired,
    enlarged: PropTypes.bool,
    isSelectable: PropTypes.bool
};

TL;DR: Conclusion

Write code that you would be proud to take home and show your mother. Your teammate and future "you" will thank you later. Once you embrace writing clean code, it will become second nature. You (and your future you) will soon appreciate the "write it and forget it" way of life.

React gives you an opportunity to write a clean and highly maintainable code. Don't waste this chance in vain.