:book: Airbnb React/JSX Style Guide
Pendekatan yang sebagian besar reasonable untuk React dan JSX
Panduan style guide ini sebagian besar didasarkan pada standar yang saat ini lazim di Javascript, meskipun beberapa konvensi (yaitu async/await atau static class fields) masih bisa dimasukkan atau dilarang berdasarkan kasus per kasus. Saat ini, apapun sebelum tahap ke 3 tidak termasuk atau direkomendasikan dalam panduan ini.
React.createClass
vs statelessisMounted
react/no-multi-comp
.React.createElement
kecuali Anda menginisialisasi aplikasi dari file yang bukan JSX.react/forbid-prop-types
akan memperbolehkan arrays
dan objects
hanya jika secara ekplisit ditulis dengan isi array
dan object
, menggunakan arrayOf
, objectOf
, atau shape
.React.createClass
vs statelessJika Anda memiliki internal state dan/atau refs, lebih baik gunakan class extends React.Component
daripada React.createClass
. eslint: react/prefer-es6-class
react/prefer-stateless-function
// buruk
const Listing = React.createClass({
// ...
render() {
return <div>{this.state.hello}</div>;
}
});
// baik
class Listing extends React.Component {
// ...
render() {
return <div>{this.state.hello}</div>;
}
}
Dan jika Anda tidak memiliki state atau refs, lebih baik gunakan fungsi biasa (bukan arrow functions) daripada classes:
// buruk
class Listing extends React.Component {
render() {
return <div>{this.props.hello}</div>;
}
}
// buruk (mengandalkan inferensi nama fungsi yang tidak disarankan)
const Listing = ({ hello }) => (
<div>{hello}</div>
);
// baik
function Listing({ hello }) {
return <div>{hello}</div>;
}
Mengapa? Mixins memperkenalkan dependensi yang implisit, menyebabkan nama tidak sesuai, dan kompleksitas snowballing. Sebagian besar kasus untuk mixins dapat diselesaikan dengan cara yang lebih baik melalui components, higher-order components, atau utility modules.
.jsx
untuk React components. eslint: react/jsx-filename-extension
ReservationCard.jsx
.Penamaan Referensi: Gunakan PascalCase untuk React components dan camelCase untuk intances nya. eslint: react/jsx-pascal-case
// buruk
import reservationCard from './ReservationCard';
// baik
import ReservationCard from './ReservationCard';
// buruk
const ReservationItem = <ReservationCard ></ReservationCard>;
// baik
const reservationItem = <ReservationCard ></ReservationCard>;
Penamaan Komponen: Gunakan nama file sebagai nama komponen. Sebagai contoh, ReservationCard.jsx
harus memiliki nama referensi dari ReservationCard
. Namun, untuk komponen root dari direktori, menggunakan index.jsx
sebagai nama file dan gunakan nama direktori sebagai nama komponen:
// buruk
import Footer from './Footer/Footer';
// buruk
import Footer from './Footer/index';
// baik
import Footer from './Footer';
Penamaan Higher-order Component: Gunakan sebuah komposit dari nama higher-order component dan nama komponen yang diteruskan sebagai displayName
pada komponen yang dihasilkan. Sebagai contoh, withFoo()
pada higher-order component , ketika melewati komponen Bar
harus menghasilkan komponen dengan displayName
dari withFoo(Bar)
.
Mengapa?
displayName
dapat digunakan oleh developer tools atau dalam pesan error, dan memiliki nilai yang secara jelas mengungkapkan hubungan untuk membantu orang memahami apa yang terjadi.
// buruk
export default function withFoo(WrappedComponent) {
return function WithFoo(props) {
return <WrappedComponent {...props} foo ></WrappedComponent>;
}
}
// baik
export default function withFoo(WrappedComponent) {
function WithFoo(props) {
return <WrappedComponent {...props} foo ></WrappedComponent>;
}
const wrappedComponentName = WrappedComponent.displayName
|| WrappedComponent.name
|| 'Component';
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
return WithFoo;
}
Penamaan Props: Hindari penggunaan nama prop pada komponen DOM untuk tujuan yang berbeda.
Mengapa? Orang akan berpikir props seperti
style
danclassName
berarti satu hal tertentu. Memvariasikan API ini untuk sebagian dari aplikasi Anda sehingga membuat kode lebih mudah dibaca dan kurang terpelihara, dan dapat menyebabkan bug.
// buruk
<MyComponent style="fancy" ></MyComponent>
// buruk
<MyComponent className="fancy" ></MyComponent>
// baik
<MyComponent variant="fancy" ></MyComponent>
Jangan gunakan displayName
untuk penamaai sebuah komponen. Sebagai gantinya, beri nama pada komponen dengan referensi.
// buruk
export default React.createClass({
displayName: 'ReservationCard',
// stuff goes here
});
// baik
export default class ReservationCard extends React.Component {
}
Ikuti alignment styles ini untuk sintaks JSX. eslint: react/jsx-closing-bracket-location
react/jsx-closing-tag-location
// buruk
<Foo superLongParam="bar"
anotherSuperLongParam="baz" ></Foo>
// baik
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
></Foo>
// jika properti dimuat dalam satu baris maka tetap pada satu baris yang sama
<Foo bar="bar" ></Foo>
// children mendapatkan indentasi secara normal
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
>
<Quux ></Quux>
</Foo>
// buruk
{showButton &&
<Button ></Button>
}
// buruk
{
showButton &&
<Button ></Button>
}
// baik
{showButton && (
<Button ></Button>
)}
// baik
{showButton && <Button ></Button>}
Selalu gunakan tanda kutip ganda ("
) untuk atribut JSX, tetapi tanda kutip tunggal ('
) untuk semua JS lainnya. eslint: jsx-quotes
Mengapa? Atribut HTML juga biasanya menggunakan tanda kutip ganda bukan tunggal, jadi atribut JSX menggunakan ketentuan ini.
// buruk
<Foo bar='bar' ></Foo>
// baik
<Foo bar="bar" ></Foo>
// buruk
<Foo style={{ left: "20px" }} ></Foo>
// baik
<Foo style={{ left: '20px' }} ></Foo>
Selalu sisipkan satu spasi di tag self-closing. eslint: no-multi-spaces
, react/jsx-tag-spacing
// buruk
<Foo></Foo>
// sangat buruk
<Foo ></Foo>
// buruk
<Foo
></Foo>
// baik
<Foo ></Foo>
Jangan menyisipkan spasi didalam kurung kurawal JSX. eslint: react/jsx-curly-spacing
// buruk
<Foo bar={ baz } ></Foo>
// baik
<Foo bar={baz} ></Foo>
Selalu gunakan camelCase untuk nama prop.
// buruk
<Foo
UserName="hello"
phone_number={12345678}
></Foo>
// baik
<Foo
userName="hello"
phoneNumber={12345678}
></Foo>
Hilangkan nama prop jika itu secara ekplisit bernilai true
. eslint: react/jsx-boolean-value
// buruk
<Foo
hidden={true}
></Foo>
// baik
<Foo
hidden
></Foo>
// baik
<Foo hidden ></Foo>
Selalu sertakan alt
prop pada setiap tag <img>
. Jika gambar adalah presentational, alt
dapat berisi string kosong atau <img>
harus memiliki role="presentation"
. eslint: jsx-a11y/alt-text
// buruk
<img src="hello.jpg" />
// baik
<img src="hello.jpg" alt="Me waving hello" />
// baik
<img src="hello.jpg" alt="" />
// baik
<img src="hello.jpg" role="presentation" />
Jangan gunakan kata-kata seperti “image”, “photo”, atau “picture” di <img>
alt
props. eslint: jsx-a11y/img-redundant-alt
Mengapa? Screenreaders sudah memberitahu elemen
img
sebagai gambar, jadi tidak perlu memberikan informasi ini didalam alt.
// buruk
<img src="hello.jpg" alt="Picture of me waving hello" />
// baik
<img src="hello.jpg" alt="Me waving hello" />
Gunakan yang sesuai, non-abstract ARIA roles. eslint: jsx-a11y/aria-role
// buruk - not an ARIA role
<div role="datepicker" ></div>
// buruk - abstract ARIA role
<div role="range" ></div>
// baik
<div role="button" ></div>
Jangan gunakan accessKey
pada elemen. eslint: jsx-a11y/no-access-key
Mengapa? Ketidakkonsistenan antara keyboard shortcuts dan keyboard commands yang digunakan oleh seseorang yang menggunakan screenreaders dan keyboards mempersulit aksesbilitas.
// buruk
<div accessKey="h" ></div>
// baik
<div ></div>
Hindari menggunakan indeks array sebagai key
pada prop, disarankan menggunakan ID yang lebih stabil. eslint: react/no-array-index-key
Mengapa? Tidak menggunakan ID adalah @robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318">anti-pattern karena dapat berdampak negatif pada kinerja dan menyebabkan masalah pada component state.
Kami tidak merekomendasikan untuk menggunakan indeks sebagai keys jika urutan item dapat berubah.
// buruk
{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
></Todo>
)}
// baik
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
></Todo>
))}
Selalu definisikan defaultProps secara ekplisit untuk semua prop yang tidak diperlukan.
Mengapa? propTypes adalah bentuk dokumentasi, dan menyediakan defaultProps yang berarti pembaca kode Anda tidak perlu berasumsi sebanyak itu.
// buruk
function SFC({ foo, bar, children }) {
return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
// baik
function SFC({ foo, bar, children }) {
return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
SFC.defaultProps = {
bar: '',
children: null,
};
Gunakan spread prop dengan hemat (sparingly).
Mengapa? kalau tidak, Anda akan lebih cenderung meneruskan properti yang tidak perlu ke komponen. Dan untuk React v15.6.1 keatas, Anda dapat mem-passing atribut HTML yang tidak valid ke DOM.
Pengecualian:
HOCs that proxy down props dan hoist propTypes
function HOC(WrappedComponent) {
return class Proxy extends React.Component {
Proxy.propTypes = {
text: PropTypes.string,
isLoading: PropTypes.bool
};
render() {
return <WrappedComponent {...this.props} ></WrappedComponent>
}
}
}
Spreading dengan objek yang dikenal, explicit props. Ini bisa sangat bergunakan ketika men-testing komponen React dengan Mocha’s beforeEach construct.
export default function Foo {
const props = {
text: '',
isPublished: false
}
return (<div {...props} ></div>);
}
Catatan untuk digunakan:
Filter prop yang tidak diperlukan jika memungkinkan. Selain itu, gunakan prop-types-exact untuk membantu mencegah bug.
// buruk
render() {
const { irrelevantProp, ...relevantProps } = this.props;
return <WrappedComponent {...this.props} ></WrappedComponent>
}
// baik
render() {
const { irrelevantProp, ...relevantProps } = this.props;
return <WrappedComponent {...relevantProps} ></WrappedComponent>
}
Selalu gunakan ref callbacks. eslint: react/no-string-refs
// buruk
<Foo
ref="myRef"
></Foo>
// baik
<Foo
ref={(ref) => { this.myRef = ref; }}
/>
Bungkus tag JSX dengan tanda kurung ketika lebih dari satu baris. eslint: react/jsx-wrap-multilines
// buruk
render() {
return <MyComponent variant="long body" foo="bar">
<MyChild ></MyChild>
</MyComponent>;
}
// baik
render() {
return (
<MyComponent variant="long body" foo="bar">
<MyChild ></MyChild>
</MyComponent>
);
}
// baik, ketika statement hanya 1 baris
render() {
const body = <div>hello</div>;
return <MyComponent>{body}</MyComponent>;
}
Selalu self-close tags yang tidak memiliki children. eslint: react/self-closing-comp
// buruk
<Foo variant="stuff"></Foo>
// baik
<Foo variant="stuff" ></Foo>
Jika komponen Anda memilki properti yang multi-line, tutup tag-nya di baris baru. eslint: react/jsx-closing-bracket-location
// buruk
<Foo
bar="bar"
baz="baz" ></Foo>
// baik
<Foo
bar="bar"
baz="baz"
></Foo>
Gunakan arrow functions untuk menutup variabel lokal. Ini berguna ketika Anda memberikan data tambahan ke event handler. Meskipun, pastikan mereka tidak secara masiv merusak peforma, khususnya ketika mem-passing ke komponen kustom yang mungkin meruapakan PureComponents, karena mereka akan men-trigger rerender yang mungkin tidak setiap waktu.
function ItemList(props) {
return (
<ul>
{props.items.map((item, index) => (
<Item
key={item.key}
onClick={(event) => { doSomethingWith(event, item.name, index); }}
/>
))}
</ul>
);
}
Bind event handlers untuk render method di constructor. eslint: react/jsx-no-bind
Mengapa? sebuah bind call di render path membuat fungsi baru disetiap single render. Jangan gunakan arrow functions di class fields, karena itu membuat mereka @charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1">challenging untuk test dan men-debug, dan dapat berdampak negatif pada performance, dan karena konseptual, class fields adalah untuk data. bukan logika.
// buruk
class extends React.Component {
onClickDiv() {
// lakukan stuff
}
render() {
return <div onClick={this.onClickDiv.bind(this)} ></div>;
}
}
// sangat buruk
class extends React.Component {
onClickDiv = () => {
// lakukan stuff
}
render() {
return <div onClick={this.onClickDiv} ></div>
}
}
// baik
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} ></div>;
}
}
Jangan gunakan awalan (prefix) untuk internal methods komponen pada React.
Mengapa? Awalan garis bawah terkadang digunakan sebagai convention dalam bahasa lain untuk menunjukan private. Tapi, tidak seperti bahasa-bahasa itu, tidak ada dukungan asli untuk private di JavaScipt, semuanya bersifat public. Terlepas dari niat Anda, menambahkan awalan garis bawah ke properti Anda sebenarnya tidak menjadikan bersifat private, dan properti apapun (underscore-prefixed atau bukan) harus diperlakukan secara public. Lihat issues #1024, dan #490 untuk diskusi yang lebih mendalam.
// buruk
React.createClass({
_onClickSubmit() {
// lakukan stuff
},
// stuff lain
});
// baik
class extends React.Component {
onClickSubmit() {
// lakukan stuff
}
// stuff lain
}
Pastikan untuk mengembalikan nilai dalam method render render
Anda. eslint: react/require-render-return
// buruk
render() {
(<div ></div>);
}
// baik
render() {
return (<div ></div>);
}
class extends React.Component
:static
opsionalconstructor
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
onClickSubmit()
atau onChangeDescription()
render
seperti getSelectReason()
atau getFooterContent()
renderNavigation()
atau renderProfilePicture()
render
How to define propTypes
, defaultProps
, contextTypes
, etc…
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',
};
class Link extends React.Component {
static methodsAreOk() {
return true;
}
render() {
return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>;
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
Ordering untuk React.createClass
: eslint: react/sort-comp
displayName
propTypes
contextTypes
childContextTypes
mixins
statics
defaultProps
getDefaultProps
getInitialState
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
onClickSubmit()
atau onChangeDescription()
render
seperti getSelectReason()
atau getFooterContent()
renderNavigation()
atau renderProfilePicture()
render
isMounted
Jangan gunakan isMounted
. eslint: react/no-is-mounted
Mengapa?
isMounted
is an anti-pattern, tidak tersedia saat menggunakan ES6 classes, dan sedang dalam perjalanan untuk secara resmi ditinggalkan.
Panduan JSX/React style ini juga tersedia dalam bahasa lain: