When developing React projects, it's essential to follow best practices to ensure code quality, maintainability, and consistency. While each project may have specific requirements, the following are some general practices that can be applied.
Basic Rules
One Component Per File: Organize your code by including only one React component per file.
Use Functional Components: Whenever possible, create functional components instead of class components. They are more concise and easier to maintain.
Always Use JSX Syntax: Ensure that you consistently use JSX syntax when defining components.
Naming
File and Component Naming: Keep your file and component names identical. Use the PascalCase naming convention for both the filename and the component name. For example:
- Bad: Filename:
header.js
const Header = () => {}
export default Header;
- Good: Filename:
Header.js
const Header = () => {}
export default Header;
Import Ordering
Organize Imports: Arrange your import statements in the following order:
a. External package imports.
b. Slice imports.
c. Component imports.
d. Sibling imports.
e. CSS module import.
Component Ordering
Component Structure: Maintain a consistent structure for your components:
a. Import statements.
b. useContext declarations.
c. useSelector declarations.
d. useState declarations.
e. useEffect blocks.
f. Event handlers such as onClickSubmit
or onChangeDescription
.
g. Getter methods for rendering, e.g., getSelectReason
or getFooterContent
.
h. Optional render methods like renderNavigation
or renderProfilePicture
.
i. render
(return statement with JSX).
j. PropTypes declaration.
k. Export statement.
Prop Types
- Define propTypes and defaultProps: Specify propTypes and defaultProps as follows:
import React from 'react';
import PropTypes from 'prop-types';
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
const Link = ({ id, url, text }) => {
return <a href={url} data-id={id}>{text}</a>
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
Alignment
Consistent Alignment: Maintain a uniform alignment for JSX attributes. For example:
Bad:
<Foo superLongParam="bar" anotherSuperLongParam="baz" />
- Good:
<Foo superLongParam="bar" anotherSuperLongParam="baz" />
- If the props fit in one line, keep them on the same line:
<Foo bar="bar" />
- Children should be indented normally:
<Foo superLongParam="bar" anotherSuperLongParam="baz">
<Spazz />
</Foo>
Quotes
- Use Double Quotes for JSX Attributes: Always use double quotes (") for JSX attributes and single quotes for all other JavaScript. For example:
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
Prop Names
Use camelCase for Prop Names: Define prop names using camelCase:
Tags
Self-Close Tags: Self-close tags that have no children:
// bad
<Foo className="stuff"></Foo>
// good
<Foo className="stuff" />
- Multi-Line Properties: If your component has multi-line properties, close its tag on a new line:
// bad
<Foo
bar="bar"
baz="baz" />
// good
<Foo
bar="bar"
baz="baz"
/>
Stateless function components
For stateless components use the function syntax, introduced in React 0.14.
// Using an ES2015 (ES6) arrow function:
const Foo = (props) => {
return <div>{props.bar}</div>;
};
// Or with destructuring and an implicit return, simply:
const Foo = ({ bar }) => (
<div>{bar}</div>
);
// Then use: <Foo bar="baz" />
PropTypes declarations
Setting propTypes declarations is mandatory
Group them into required/none-required
Alphabetically sort each group
Separate them by a new line
static propTypes = {
blank: React.PropTypes.bool.isRequired,
block: React.PropTypes.bool.isRequired,
size: React.PropTypes.string.isRequired,
to: React.PropTypes.string.isRequired,
disabled: React.PropTypes.bool,
};
Using handler methods
Name methods using
'handle' + triggering event
, e.g.handleClick
Bind handler using the ES6 arrow syntax, so inside the callback, it has always the right context
const Foo = () => {
const [isClicked, setIsClicked] = useState(false);
handleClick = (e) => {
setIsClicked(!isClicked);
}
return (
<button onClick={handleClick}>Submit</button>
);
}
Using “container” components for loading data from Stores
Container Components: Separate data loading logic into container components.
// CommentListContainer.js
const CommentListContainer = () => {
const [comments, setComments] = useState([]);
useEffect(() => {
(async () => {
const response = await fetch("/my-comments.json");
const data = await response.json();
setComments(data);
})();
}, []);
return <CommentList comments={comments} />;
};
// CommentList.js
const CommentList = (props) => {
const renderComment = ({ body, author }) => {
return (
<li>
{body}—{author}
</li>
);
};
return <ul> {props.comments.map(renderComment)} </ul>;
};
Closing Components without children
When closing components without children, use self-closing tags:
return (
<Foo>
<Bar />
</Foo>
);
List iterations
When rendering a list of components from an array, do it inline if it makes sense. If the map function is too long or complicated, consider extracting it out into its own method on the component
const [fooList, setFooList] = useState(['orange', 'fish curry']);
return (
<ul>
{fooList.map((fooItem) => (
<FooItem>{fooItem}</FooItem>
))}
</ul>
);
Formatting Attributes
Maintain consistent formatting for attributes, especially for input elements:
const [foo, setFoo] = useState("apple");
const handleInputChange = (e) => {
setFoo(e.target.value);
};
return (
<input
type="text"
value={foo}
onChange={(e)=>handleInputChange(e)}
/>
);
Inline CSS styles
Set static CSS properties in SCSS and dynamic ones in JavaScript:
.Foo {
background-color: #ff0;
}
import React from "react";
const Foo = () => {
const [position, setPosition] = React.useState(0);
const styles = { transform: "translateX(" + position + "px)" };
return (
<div className="Foo" style={styles}>
Foo Header
</div>
);
};
export default Foo;
Use "classnames" to set CSS classes
Use the classnames node module for setting CSS classes on an element.
import React from 'react';
import classnames from 'classnames';
const Foo = () => {
const classes = classnames('FooHeader', {
'is-fixed': this.state.fixed,
'is-visible': this.state.visible,
});
return <div className={classes}>Foo Header</div>;
};
export default Foo;
These best practices will help you maintain a clean, organized, and consistent codebase while working on React projects. Keep in mind that specific project requirements may lead to some adjustments in these guidelines.