NOTE: This should be an ever changing document that is kept up to the date with the teams standard.
- import order is important. No spaces should be added in between import statement. It is not needed as an identifier between different "imports types". The order is as follows:
- Libraries (react, prop-types, lodash, etc.)
- Utility functions (lib/axios, utils/doSomeCommonAction)
- Components
- Containers
- When testing components, it is helpful to provide a named export of the component declaration to avoid having to deal with HoCs like react-redux#compose. Then you can mock redux's mapped props and state and just test what you need on the component.
- The order of the classes static properties should be preserved in the order of
- propTypes
- contextTypes
- childContextTypes
- defaultProps
- The use of constructors are not needed.
- If you need to add state, declare it inline as a class property.
- If you need to bind a method, declare it as a class property and assign an arrow function to it to which auto binds the
this
keyword.
- propTypes should be defined as an object property of the functional component.
- defaultProps should be defined for any non required props.
- Lifecycle method ordering portrayed in template, should persist.
- Overall ordering, for all class properties and methods, portrayed in template should persist.
- Event handler convention.
- Should follow the pattern on.
- Should be arrow functions assigned as class properties.
- Should generally not be an inline function in render.
- Getter methods
- Returns computed data based information that this component is already aware of (props and state). No xhr requests should be made here.
- Optional render methods
- The naming pattern should be render
- Be mindful when using this, it may be an identifier that you have an opportunity to break out this UI into another component.
- Render method should always be the last method declared.
- The default export is where we decorate our component with HoCs. This should happen at the bottom of the file.
// Libraries (react, prop-types, lodash, etc.)
import React, { Component } from 'react';
import PropTypes from 'prop-types';
// Utility functions (lib/axios, utils/doSomeCommonAction)
// Containers
// Components
export class MyComponent extends Component {
static propTypes = {};
static contextTypes = {};
static childContextTypes = {};
static defaultProps = {};
state = {};
getChildContext() {}
componentWillMount() {}
componentDidMount() {}
componentWillReceiveProps() {}
shouldComponentUpdate() {}
componentWillUpdate() {}
componentDidUpdate() {}
componentWillUnmount() {}
// Event handlers
onClickDescriptor = ev => {};
onChangeDescriptor = ev => {};
// Getter methods
getDescriptor() {}
// Optional render methods
renderDescriptor() {}
render() {
return null;
}
}
export default MyComponent;
- import order is important. No spaces should be added in between import statement. It is not needed as an identifier between different "imports types". The order is as follows:
- Libraries (react, prop-types, lodash, etc.)
- Utility functions (lib/axios, utils/doSomeCommonAction)
- Components
- Containers
- When testing components, it is helpful to provide a named export of the component declaration to avoid having to deal with HoCs like react-redux#compose. Then you can mock redux's mapped props and state and just test what you need on the component.
- All event handlers should be passed down from props and not declared as inline functions.
- propTypes should be defined as an object property of the functional component.
- defaultProps should be defined for any non required props.
// Libraries (react, prop-types, lodash, etc.)
import React, { Component } from 'react';
import PropTypes from 'prop-types';
// Utility functions (lib/axios, utils/doSomeCommonAction)
// Containers
// Components
export function MyFunctionalComponent(props) {
return <Button onClick={props.onClickHandleAction} />;
}
MyFunctionalComponent.propTypes = {};
MyFunctionalComponent.defaultProps = {};
export default MyFunctionalComponent;
- Only include one React component per file.
- However, multiple Stateless, or Pure, Components are allowed per file.
- Always use JSX syntax.
- Do not use
React.createElement
unless you're initializing the app from a file that is not JSX.
-
Always use camel case for prop names
<Button handleClick={this.onClickButton} /> // vs <Button handle-click={this.onClickButton} />
-
Do not pass static true values to boolean props.
<Button disabled /> // vs <Button disabled={true} />
-
Spread props:
- Use spread props sparingly and filter out unnecessary props when possible.
- Should we use prop-types-exact?
- All HoCs should spread props down to WrappedComponent.
-
We use ES6 class syntax and no longer write new components with the createClass API since it no longer available in React 16+.
-
If you don't need state, context, or refs, prefer normal functions over classes.
-
Classes should use static properties instead of adding them after the class declaration.
// bad class MyComponent extends Component {} MyComponent.propTypes = {}; // good class MyComponent extends Component { static propTypes = {}; }
- Mixins do not work with ES6 classes, thus are not to be used for any new components.
-
Extensions: Use
.js
extension for React components. -
Methods Do not use underscore prefix for internal methods of a React component. Method names should be camelCase.
-
Filename: Use PascalCase for filenames. E.g.,
ReservationCard.js
. -
Reference Naming: Use PascalCase for React components and camelCase for their instances.
// bad import reservationCard from './ReservationCard'; // good import ReservationCard from './ReservationCard'; // bad const ReservationItem = <ReservationCard />; // good const reservationItem = <ReservationCard />;
-
Component Naming: Use the filename as the component name. For example,
ReservationCard.js
should have a reference name ofReservationCard
. However, for root components of a directory, useindex.js
as the filename and use the directory name as the component name:// bad import Footer from './Footer/Footer'; // bad import Footer from './Footer/index'; // good import Footer from './Footer';
-
Higher-order Component Naming: HoCs should be named with the convention of with and be camelCase. If the returned component is a class, then the name should be same name as the outer function and should be PascalCase, so With. Use a composite of the higher-order component's name and the passed-in component's name as the
displayName
on the generated component. For example, the higher-order componentwithFoo()
, when passed a componentBar
should produce a component with adisplayName
ofwithFoo(Bar)
.Why? A component's
displayName
may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening.// bad export default function withFoo(WrappedComponent) { return function WithFoo(props) { return <WrappedComponent {...props} foo />; } } // good export default function withFoo(WrappedComponent) { function WithFoo(props) { return <WrappedComponent {...props} foo />; } const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; WithFoo.displayName = `withFoo(${wrappedComponentName})`; return WithFoo; }
-
Props Naming: Avoid using DOM component prop names for different purposes.
Why? People expect props like
style
andclassName
to mean one specific thing. Varying this API for a subset of your app makes the code less readable and less maintainable, and may cause bugs.// bad <MyComponent style="fancy" /> // bad <MyComponent className="fancy" /> // good <MyComponent variant="fancy" />
I drew inspiration, content and examples from the AirBnb React style guide.