• Our Best Practices for Writing React Components
  • Scott Domes
  • The Nuggets translation Project
  • Translator: imink
  • Proofreader: L9m Ethan

When I first started writing React, I remember there were many different ways to write components, and each tutorial was quite different. While the React framework has matured considerably since then, there still doesn’t seem to be a clear “right” way to write components.

During MuseFind’s work over the past year, our team has written countless React components. We are constantly improving our methods until we are satisfied.

This guide suggests the best way to write the React component. Whether you’re a beginner or an experienced person, we hope you find it useful.

Before we get started, some notes:

  • We use ES6 and ES7 syntax.
  • If you are not familiar with presentation and container components, we recommend reading this article first.
  • Please feel free to comment, leave your suggestions, questions and feedback.

Class-based components

Class-based components contain state and methods. We should use them as sparingly as possible, but such components have their place.

Next, let’s build our component line by line

Initialization state

import React, {Component} from 'react'
import {observer} from 'mobx-react'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

export default class ProfileContainer extends Component {
  state = { expanded: false }Copy the code

If you are using ES6 instead of ES7, initialize the state in the constructor. In addition, you can use the above method to initialize state in ES7. For more information, please go here.

Of course, we also need to export our class as the default.

methods

import React, {Component} from 'react'
import {observer} from 'mobx-react'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

export default class ProfileContainer extends Component {
  state = { expanded: false }

  static propTypes = {
    model: React.PropTypes.object.isRequired,
    title: React.PropTypes.string
  }

  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }

  handleSubmit = (e) = > {
    e.preventDefault(a)this.props.model.save()}handleNameChange = (e) = > {
    this.props.model.name = e.target.value
  }

  handleExpand = (e) = > {
    e.preventDefault(a)this.setState({ expanded: !this.state.expanded})}Copy the code

In class-based components, when you need to pass methods to child components, you should ensure that they are properly bound to this when called. This is usually done by passing this.handlesubmit.bind (this) to a child component.

We think this approach is simpler and easier to use, with ES6’s arrow function automatically ensuring the correct context.

A decorator

@observer
export default class ProfileContainer extends Component {Copy the code

If you use a tool like Mobx, you can decorate components as above, just like passing components to functions.

Decorators are a flexible and readable way to modify a component’s functionality, and with Mobx and our own Mobx-Models library, we can use them extensively.

If you don’t want to use decorators, here’s what you can do:

class ProfileContainer extends Component {
  // Component code
}

export default observer(ProfileContainer)Copy the code

Function component

This part of the component has no state or methods. Such components are relatively pure and easy to understand. Use these components as often as possible.

Deconstruct Props and defaultProps

import React from 'react'
import {observer} from 'mobx-react'

import './styles/Form.css'

const expandableFormRequiredProps = {
  onSubmit: React.PropTypes.func.isRequired,
  expanded: React.PropTypes.bool
}

function ExpandableForm(props) {
  return (
    <form style={props.expanded ? {height: 'auto'} : {height: 0}}>
      {props.children}
      <button onClick={props.onExpand}>Expand</button>
    </form>)}Copy the code

Our component is a function with props as the argument. We can expand it like this:

import React from 'react'
import {observer} from 'mobx-react'

import './styles/Form.css'

const expandableFormRequiredProps = {
  onExpand: React.PropTypes.func.isRequired,
  expanded: React.PropTypes.bool
}

function ExpandableForm({ onExpand, expanded = false, children }) {
  return (
    <form style={ expanded ? { height: 'auto' } : { height: 0}}>
      {children}
      <button onClick={onExpand}>Expand</button>
    </form>)}Copy the code

Note that we can use the default parameter as defaultProps in a more readable way. If expanded is not defined, we set it to false. (A more plausible explanation is that although it is a Boolean type, it avoids the problem of object errors such as’ Cannot read < property > of undefined ‘).

Avoid the following ES6 syntax:

const ExpandableForm = ({ onExpand, expanded, children }) = > {Copy the code

It looks pretty snazzy, but the function here is actually unnamed.

If Babel is set correctly, not naming here is not a problem. But if Babel is set wrong, any errors will be rendered as << anonymous >>, which is a very bad experience for tuning errors.

Unnamed functions can also cause problems with Jest (a React test library). Because of the potential problems of these difficult to understand bugs, we recommend using function instead of const.

Conditional statements in JSX

If you’re going to use a lot of conditional rendering, here’s what you need to avoid:

Nested ternary operators are not a good idea.

While there are some third-party libraries that address this issue (JSX-Control Statements), here we use the following approach to resolve complex conditional Statements without referring to these dependencies.

Wrap an IIFE with curly braces, then put an if statement inside to return whatever you want to render. Note that IIFE can cause performance problems, but in most cases it does not cause performance problems comparable to code readability problems.

Similarly, when you only want to render an element in a conditional statement, don’t do this:

{
  isTrue
   ? <p>True!</p>
   : <none/>
}Copy the code

Short-circuit evaluation should be used

{
  isTrue && 
    <p>True!</p>
}Copy the code

After the