While we explore the React library, this repository will act as a React style guide containing best practices and examples.
Utilize ES6
When building a React application, it's recommended to use ES6. ECMAScript 2015 provides developers with many advancements such as classes, spread operator, for-of loop, arrow functions, etc.
Component Hierarchy
export default class Foo extends React.Component {
constructor(props) {
super(props)
this.__myCustomMethodTwo = this.__myCustomMethodTwo.bind(this)
this.__myCustomMethodTwo = this.__myCustomMethodTwo.bind(this)
}
componentWillMount() {}
componentDidMount() {}
componentWillReceiveProps() {}
shouldComponentUpdate() {}
componentWillUpdate() {}
componentDidUpdate() {}
componentWillUnmount() {}
__myCustomMethodOne() {}
__myCustomMethodTwo() {}
render() {
return (
<div></div>
)
}
}
Opt for stateless components
Components shouldn't have too much state. State makes components difficult to test and reason about.
Utilize class extensions
JavaScript Classes provide a much simpler and clearer syntax to create objects and deal with inheritance. React Components should be created using Classes.
Default NPM config
Add the following to a .npmrc
file in your project root. This will automatically save (and remove) dependencies installed with npm i
or npm i -D
.
save=true
save-exact=true
Default eslint config
Add some basic linting to your project by including the following snippets in your package.json
file.
Note: Be sure to update the
devDependencies
section with appropriate versions.
{
"eslintConfig": {
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single",
{
"allowTemplateLiterals": true
}
],
"semi": [
"error",
"never"
]
}
},
"devDependencies": {
"eslint": "3.0.0"
},
"scripts": {
"test:lint": "eslint **/*.js"
}
}
Default babel config
Note: Be sure to update the
devDependencies
section with appropriate versions.
{
"babel": {
"presets": [
"react"
]
},
"devDependencies": {
"babel-core": "6.14.0", // or latest version
"babel-preset-react": "6.11.1" // or latest version
}
}
Prefix event handlers
Prefix all event handlers with two underscores followed by the word "handle".
__handleOnClick {}
Bind handler methods in the component's constructor
When using Classes with React Components, there's no autobinding. You should bind your event handlers in the constructor so they are only bound once for every instance.
constructor(props) {
super(props)
this.__handleOnClick = this.__handleOnClick.bind(this)
}
Separate Components To better understand the functionality of components, it's recommended to separate basic components from routes and components from container components.
Routes # Pages
Components # Piece of Functionality
Containers # Layout/Templates
Fix React warnings, do not ignore them
React warners should never go unnoticed. If there is an issue, fix it immediately.
Always declare your propTypes
Always declare what props your component expects and what they do. This will specify a validation function for each prop it's set to receive. If validation function fails, a warning will be logged in the console.
Foo.propTypes = {
text: PropTypes.string,
completed: Proptypes.bool
seats: React.PropTypes.number,
settings: React.PropTypes.object,
callback: React.PropTypes.func
}
Render Return
If the element will fit on one 80 character line, then inline it.
render() {
return (
<div>This element fits on one 80 character line. This can be inlined.</div>
)
}
JSX Quote Formatting
Always use double quotes for JSX string properties. Otherwise, use single quotes.
render() {
return(
<button className="title" onClick="this.__handleOnClick">Click Me</button>
)
}
Connect Redux Store to Containers Using Connect()
When connecting your Container components to the store, use connect() from react-redux and set up mapStateToProps and mapDispatchToProps.
import React from 'react'
import { connect } 'react-redux'
class Foo extends React.component {
constructor(super) {
props(super)
}
render() {
return (<div>Hello World</div>)
}
}
const mapStateToProps = (state, ownProps) => {
return {
}
}
const mapDispatchToProps = (state) => {
return {
}
}
const Foo = connect(
mapStateToProps,
mapDispatchToProps
)(Foo)
export default Foo
To make our apps easy to understand and help keep them organized, this structure should be used:
├── /node_modules/ # 3rd-party libraries and utilities
├── /src/ # The source code of the application
│ ├── /client/ # Client side files
│ │ ├── /assets/ # All assets files
│ │ ├── /scripts/ # Contains javascript files for app
│ │ │ ├── /actions/ # Payloads of data that send data to the store
│ │ │ ├── /components/ # Components meant for Pieces of Functionality
│ │ │ ├── /containers/ # Components meant for Layouts/Templates
│ │ │ ├── /reducers/ # Pure function that returns the next state based off of actions
│ │ │ ├── /routes/ # Components meant for Pages
│ │ │ ├── /store/ # Manages the application state
│ │ │ ├── /utilities/ # Utilities such as libraries or common tools
│ │ │ └── index.js # App entry point. Connects store to App and contains routes
│ │ └── /styles/ # Contains the LESS and CSS for the app
│ │ ├── _global_styles.scss # Global styling for application
│ │ ├── _local_variables.scss # Local variables for styling
│ │ ├── _typography.scss # Typography styling
│ │ ├── index.scss # Entry point for styling
│ │ └── reset.css # Standard normalize/reset stylesheet
│ └── /server/ # Server side files
│ ├── /middleware/ # Additional server functionality
│ ├── /models/ # Application Models (i.e. business logic)
│ ├── /routes/ # Controller map to routes (i.e. urls)
│ ├── /scripts/ # Various entry points
│ ├── /views/ # Template files
│ ├── app.js # Express application server
│ └── index.js # Exports happen here
├── /test/ # The source code of the application
│ ├── /client/ # Client side test files
│ │ ├── /function/ # Test functionality across components
│ │ ├── /unit/ # Test small, critical pieces of functionality
│ │ ├── /utils/ # Utilities used to prepare test cases
│ │ ├── env.js # Setup the test application environment
│ │ └── setup.js # Global test setup goes here
│ └── /server/ # Server side test files
│ ├── /function/ # Test functionality across components
│ ├── /unit/ # Test small, critical pieces of functionality
│ ├── /utils/ # Utilities used to prepare test cases
│ ├── env.js # Setup the test application environment
│ └── setup.js # Global test setup goes here
├── .gitignore # Ignore certain files and folders
├── .npmrc # Default NPM config
├── index.html # Application's HTML Entry Point
├── package.json # NPM Packages
├── readme.md # Important Information
├── server.js # Development server configuration
└── webpack.config.js # Webpack configuration
A list of primary dependencies we use:
React # Application library
React-Router # Create and manage routes for application
Redux # Manage application state and data
Webpack # A modular JavaScript bundler
Babel # JavaScript compiler
Node-sass # Sass for styling
Eslint # JavaScript linter