This is our style guide for how we write our react code at VTS. Some of them are preferences, but if we all try to stick to them as much as possible hopefully we can have a maintainable, easy to read codebase. If something is not listed here, then we generally abide by the AirBnB's react style guide. If it's not in there either, use your best judgement.
These are some rules to help us try to keep a clean, readable, bug-free codebase. The more we standardize on some of these simple style rules, the easier it will be to jump into someone else's code and understand what's going on.
- 1.1 Prefer specific module imports over global imports for libraries
// correct
import map from 'lodash/map'
// incorrect
import { map } from 'lodash'- 1.2 Prop naming and declaration
- Put the
propTypesdeclaration at the bottom of the file - Action props start with
on - Method to be passed to an
onSomeActionHappenedprop should start withhandle
- Put the
// SomeComponent.js
export const SomeComponent = () => <div></div>;
SomeComponent.propTypes = {
// Default handler if you have a single value
onChange: PropTypes.func,
// Default name for model if you only have one data binding
value: PropTypes.any,
};
// UseSomeComponent.js
export class UseSomeComponent extends Component {
handleSomeChange = () => { /* Do whatever you need to do onChange of SomeComponent */ };
render() {
return <SomeComponent onChange={this.handleSomeChange} />;
}
};- 1.3 Prefer class field declarations instead of binding in the constructor
// incorrect
export class SomeComponent extends Component {
constructor() {
this.state = {
inputModel: ""
};
this.handleInputChange = () => { /* Do what you have gotta do */ };
SomeService.find().then(() => { /* Do a thing */ });
}
};
// correct
export class SomeComponent extends Component {
state = {
inputModel: ""
};
handleInputChange = () => { /* Do what you gotta do */ };
constructor() {
SomeService.find().then(() => { /* Do a thing */ });
}
};- 1.4 Inside of JSX, only use ternary operators and avoid boolean operators
- This helps us be more speciefic with our return values, as well as conveying intent of the resolved value to the reader.
// incorrect
export const SomeComponent = ({ showIcon = true }) => (
<div>
// this could return any falsey value, e.g. 0
{ showIcon && (<i class="icon-mag" />) }
<span>Hello, world!</span>
</div>
);
// correct
export const SomeComponent = ({ showIcon = true }) => (
<div>
// this is much more specific, will always return only either <i /> or null
{ showIcon ? <i class="icon-mag" /> : null }
<span>Hello, world!</span>
</div>
);- 1.5 Use Pascal case if you're importing a full library import, camel case if it's just a function or util
- Whether it's the default import or a named import, doing this lets us more easily read usage of our 3rd party libraries
// incorrect
import propTypes from "prop-types";
import ClassNames from "classNames";
import Map from "lodash/map";
import Flatten from "lodash/flatten";
// correct
import PropTypes from "prop-types";
import classNames from "classNames";
import map from "lodash/map";
import flatten from "lodash/flatten";This is for larger questions, e.g. where should I put files, how should I test components, etc.
- 2.1 Our current testing framework consists of:
- 2.2 Our overall folder structure is approximately as follows:
- A couple different root directories at the top level in
react-ui:views: All components that are page specific. Grouped by business case.shared: All shared components.
- File naming:
- Services:
vts-core/services/comps/comps-service.js - React components:
react-ui/shared/Modal.js - Angular components:
angular-ui/proposal-form/new-proposal-form.js
- Services:
- Folder naming:
- Always kebab case
- A couple different root directories at the top level in
Don't use Angular! Kidding (but not really). This section is for any changes in libraries that we're trying to implement, whether it be a different usage of an existing dependency or deprecation of a lib in our app.
- 3.1 Prefer to not use jQuery when at all possible
- 3.2 Prefer native APIs over lodash. If there's a reason to use lodash then it's fine.
- 3.3 Always use
ngto import to access angular service dependencies if their data is not in the redux store already