Menulis kode bersih adalah keterampilan yang menjadi kewajiban pada tahap tertentu dalam karier seorang programmer. Keterampilan ini sangat penting ketika programmer mencoba menemukan pekerjaan pertamanya. Ini, pada dasarnya, adalah apa yang membuat pengembang menjadi pemain tim, dan sesuatu yang bisa "mengisi" wawancara, atau membantunya berhasil lulus. Pengusaha, ketika membuat keputusan personalia, lihat kode yang ditulis oleh karyawan potensial mereka. Kode yang ditulis oleh programmer harus dipahami tidak hanya oleh mesin, tetapi juga oleh orang-orang.

Materi, bagian pertama dari terjemahan yang kami terbitkan hari ini, menyajikan tips untuk menulis kode bersih untuk aplikasi Bereaksi. Relevansi tips ini adalah semakin tinggi, semakin besar ukuran proyek di mana prinsip-prinsip yang ditetapkan di dalamnya diterapkan. Dalam proyek kecil, Anda mungkin dapat melakukannya tanpa menerapkan prinsip-prinsip ini. Ketika memutuskan apa yang dibutuhkan dalam setiap situasi tertentu, ada baiknya dibimbing oleh akal sehat.
1. Merusak properti
Properti perusakan (dalam istilah Bahasa Inggris Bereaksi mereka disebut "alat peraga") adalah cara yang baik untuk membuat kode lebih bersih dan meningkatkan kemampuan dukungannya. Faktanya adalah ini memungkinkan Anda untuk dengan jelas mengungkapkan atau menyatakan apa yang digunakan entitas (seperti komponen Bereaksi). Namun, pendekatan ini tidak memaksa pengembang untuk membaca implementasi komponen untuk mengetahui komposisi properti yang terkait dengannya.
Properti perusakan juga memungkinkan programmer untuk menetapkan nilai default. Ini sangat umum:
import React from 'react' import Button from 'components/Button' const MyComponent = ({ placeholder = '', style, ...otherProps }) => { return ( <Button type="button" style={{ border: `1px solid ${placeholder ? 'salmon' : '#333'}`, ...style, }} {...otherProps} > Click Me </Button> ) } export default MyComponent
Salah satu konsekuensi paling menyenangkan dari menggunakan destrrukturisasi dalam JavaScript, yang dapat saya temukan, adalah memungkinkan Anda untuk mendukung berbagai opsi untuk parameter.
Misalnya, kami memiliki fungsi
authenticate
, yang menggunakan parameter
token
digunakan untuk mengautentikasi pengguna. Kemudian penting untuk membuatnya menerima entitas
jwt_token
. Kebutuhan ini disebabkan oleh perubahan struktur respons server. Berkat penggunaan perusakan, Anda dapat dengan mudah mengatur dukungan untuk kedua parameter tanpa harus berurusan dengan kebutuhan untuk mengubah sebagian besar kode fungsi:
jwt_token
akan dievaluasi ketika kode mencapai
token
. Akibatnya, jika
jwt_token
ternyata token yang valid, dan entitas
token
ternyata tidak
undefined
, nilai
jwt_token
akan jatuh ke dalam
token
. Jika dalam
token
sudah ada beberapa nilai yang tidak salah oleh aturan JS (yaitu, beberapa token nyata), maka dalam
token
hanya akan ada apa yang sudah ada di sana.
2. Tempatkan file komponen dalam struktur folder yang dipikirkan dengan matang
Lihatlah struktur direktori berikut:
- src
- komponen
- Breadcrumb.js
- CollapsedSeparator.js
- Masukan
- index.js
- Input.js
- utils.js
- focusManager.js
- Kartu
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
Remah roti dapat mencakup pemisah. Komponen
CollapsedSeparator
diimpor dalam file
Breadcrumb.js
. Ini memberi kita pengetahuan bahwa dalam pelaksanaan proyek tersebut mereka terhubung. Namun, seseorang yang tidak memiliki informasi ini dapat menyarankan bahwa
Breadcrumb
dan
CollapsedSeparator
adalah sepasang komponen yang sepenuhnya independen yang tidak terhubung satu sama lain dengan cara apa pun. Terutama - jika
CollapsedSeparator
tidak
CollapsedSeparator
tanda-tanda yang jelas bahwa komponen ini dikaitkan dengan komponen
Breadcrumb
. Di antara tanda-tanda tersebut, misalnya, mungkin ada awalan
Breadcrumb
digunakan dalam nama komponen, yang dapat mengubah nama menjadi sesuatu seperti
BreadcrumbCollapsedSeparator.js
.
Karena kita tahu bahwa
Breadcrumb
dan
CollapsedSeparator
terkait satu sama lain, kita mungkin bertanya-tanya mengapa mereka tidak ditempatkan di folder yang terpisah, seperti
Input
dan
Card
. Pada saat yang sama, kita dapat mulai membuat berbagai asumsi tentang mengapa bahan-bahan proyek memiliki struktur seperti itu. Katakanlah, di sini Anda dapat berpikir tentang apa komponen-komponen ini ditempatkan pada tingkat atas proyek untuk membantu mereka dengan cepat menemukan komponen-komponen ini, merawat mereka yang akan bekerja dengan proyek tersebut. Akibatnya, hubungan antara bagian-bagian proyek terlihat agak kabur bagi pengembang baru. Penggunaan teknik penulisan kode bersih harus memiliki efek sebaliknya. Intinya adalah bahwa berkat mereka, pengembang baru mendapat kesempatan untuk membaca kode orang lain dan langsung memahami esensi situasi.
Jika kita menggunakan struktur direktori yang dipikirkan dengan matang dalam contoh kita, kita mendapatkan sesuatu seperti berikut:
- src
- Remah roti
- index.js
- Breadcrumb.js
- CollapsedSeparator.js
- Masukan
- index.js
- Input.js
- utils.js
- focusManager.js
- Kartu
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
Sekarang tidak masalah berapa banyak komponen yang terkait dengan komponen
Breadcrumb
akan dibuat. Selama file-file mereka terletak di direktori yang sama dengan
Breadcrumb.js
, kita akan tahu bahwa mereka terkait dengan komponen
Breadcrumb
:
- src
- Remah roti
- index.js
- Breadcrumb.js
- CollapsedSeparator.js
- Expander.js
- BreadcrumbText.js
- Breadcrumbhothotog.js
- Breadcrumbfishes.js
- Breadcrumbleftft.js
- Breadcrumbhead.js
- Breadcrumbaddict.js
- Breadcrumbdragon0814.js
- Breadcrumbcontext.js
- Masukan
- index.js
- Input.js
- utils.js
- focusManager.js
- Kartu
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
Ini adalah bagaimana bekerja dengan struktur serupa terlihat dalam kode:
import React from 'react' import Breadcrumb, { CollapsedSeparator, Expander, BreadcrumbText, BreadcrumbHotdog, BreadcrumbFishes, BreadcrumbLeftOvers, BreadcrumbHead, BreadcrumbAddict, BreadcrumbDragon0814, } from '../../../../../../../../../../components/Breadcrumb' const withBreadcrumbHotdog = (WrappedComponent) => (props) => ( <WrappedComponent BreadcrumbHotdog={BreadcrumbHotdog} {...props} /> ) const WorldOfBreadcrumbs = ({ BreadcrumbHotdog: BreadcrumbHotdogComponent, }) => { const [hasFishes, setHasFishes] = React.useState(false) return ( <BreadcrumbDragon0814 hasFishes={hasFishes} render={(results) => ( <BreadcrumbFishes> {({ breadcrumbFishes }) => ( <BreadcrumbLeftOvers.Provider> <BreadcrumbHotdogComponent> <Expander> <BreadcrumbText> <BreadcrumbAddict> <pre> <code>{JSON.stringify(results, null, 2)}</code> </pre> </BreadcrumbAddict> </BreadcrumbText> </Expander> {hasFishes ? breadcrumbFishes.map((fish) => ( <> {fish} <CollapsedSeparator /> </> )) : null} </BreadcrumbHotdogComponent> </BreadcrumbLeftOvers.Provider> )} </BreadcrumbFishes> )} /> ) } export default withBreadcrumbHotdog(WorldOfBreadcrumbs)
3. Beri nama komponen menggunakan konvensi penamaan standar
Menggunakan standar tertentu ketika memberi nama komponen memudahkan seseorang yang bukan penulis proyek untuk membaca kode untuk proyek ini.
Misalnya, nama
komponen tingkat tinggi (HOC) biasanya diawali
with
. Banyak pengembang yang menggunakan nama komponen ini:
import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import getDisplayName from 'utils/getDisplayName' const withFreeMoney = (WrappedComponent) => { class WithFreeMoney extends React.Component { giveFreeMoney() { return 50000 } render() { return ( <WrappedComponent additionalMoney={[ this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), ]} {...this.props} /> ) } } WithFreeMoney.displayName = `withFreeMoney(${getDisplayName( WrappedComponent, )}$)` hoistNonReactStatics(WithFreeMoney, WrappedComponent) return WithFreeMoney } export default withFreeMoney
Misalkan seseorang memutuskan untuk mundur dari praktik ini dan melakukan ini:
import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import getDisplayName from 'utils/getDisplayName' const useFreeMoney = (WrappedComponent) => { class WithFreeMoney extends React.Component { giveFreeMoney() { return 50000 } render() { return ( <WrappedComponent additionalMoney={[ this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), ]} {...this.props} /> ) } } WithFreeMoney.displayName = `useFreeMoney(${getDisplayName( WrappedComponent, )}$)` hoistNonReactStatics(WithFreeMoney, WrappedComponent) return WithFreeMoney } export default useFreeMoney
Ini adalah kode JavaScript yang berfungsi sempurna. Nama-nama di sini dibuat, dari sudut pandang teknis, benar. Tetapi awalan
use
biasa digunakan dalam situasi lain, yaitu saat memberi nama
React hooks . Akibatnya, jika seseorang menulis sebuah program yang mereka rencanakan untuk ditunjukkan kepada orang lain, ia harus berhati-hati tentang nama-nama entitas. Ini terutama benar untuk kasus-kasus ketika seseorang meminta untuk melihat kode dan membantunya memecahkan masalah. Faktanya adalah bahwa seseorang yang membaca kode orang lain, sangat mungkin, sudah terbiasa dengan skema penamaan entitas tertentu.
Penyimpangan dari standar yang diterima secara umum membuat sulit untuk memahami kode orang lain.
4. Hindari Boolean Traps
Programmer harus sangat berhati-hati jika beberapa output tergantung pada beberapa nilai logis primitif, dan beberapa keputusan dibuat berdasarkan analisis nilai-nilai ini. Ini menyinggung kode kualitas yang buruk. Ini memaksa pengembang untuk membaca kode untuk menerapkan komponen atau mekanisme lain untuk mendapatkan ide yang akurat tentang apa hasil dari mekanisme ini.
Misalkan kita membuat komponen
Typography
yang dapat menerima opsi berikut:
'h1'
,
'h2'
,
'h3'
,
'h4'
,
'h5
',
'h6'
,
'title'
,
'subheading'
.
Apa tepatnya yang akan memengaruhi output suatu komponen jika opsinya dilewatkan dalam bentuk berikut?
const App = () => ( <Typography color="primary" align="center" subheading title> Welcome to my bio </Typography> )
Mereka yang memiliki pengalaman dengan Bereaksi (atau, lebih tepatnya, dengan JavaScript) mungkin sudah mengasumsikan bahwa opsi
title
akan
subheading
opsi
subheading
karena cara sistem bekerja. Opsi terakhir akan menimpa yang pertama.
Tetapi masalahnya di sini adalah bahwa kita tidak bisa, tanpa melihat ke dalam kode, mengatakan dengan tepat sejauh mana opsi
title
atau opsi
subheading
akan diterapkan.
Sebagai contoh:
.title { font-size: 1.2rem; font-weight: 500; text-transform: uppercase; } .subheading { font-size: 1.1rem; font-weight: 400; text-transform: none !important; }
Meskipun
title
menang,
text-transform: uppercase
CSS
text-transform: uppercase
aturan
text-transform: uppercase
tidak akan berlaku. Ini disebabkan oleh kekhususan
text-transform: none !important
lebih tinggi
text-transform: none !important
Aturan
text-transform: none !important
yang ada di
subheading
. Jika Anda tidak berhati-hati dalam situasi seperti itu, men-debug kesalahan seperti itu dalam gaya bisa menjadi sangat sulit. Terutama - dalam kasus di mana kode tidak menampilkan beberapa peringatan atau pesan kesalahan di konsol. Ini dapat memperumit tanda tangan komponen.
Salah satu solusi yang mungkin untuk masalah ini adalah dengan menggunakan versi yang lebih bersih dari komponen
Typography
:
const App = () => <Typography variant="title">Welcome to my bio</Typography>
Berikut adalah kode komponen
Typography
:
import React from 'react' import cx from 'classnames' import styles from './styles.css' const Typography = ({ children, color = '#333', align = 'left', variant, ...otherProps }) => { return ( <div className={cx({ [styles.h1]: variant === 'h1', [styles.h2]: variant === 'h2', [styles.h3]: variant === 'h3', [styles.h4]: variant === 'h4', [styles.h5]: variant === 'h5', [styles.h6]: variant === 'h6', [styles.title]: variant === 'title', [styles.subheading]: variant === 'subheading', })} > {children} </div> ) }
Sekarang, ketika dalam komponen
App
kita beralih ke
variant="title"
komponen
Typography
variant="title"
, kita dapat yakin bahwa hanya
title
akan memengaruhi keluaran komponen. Ini menyelamatkan kita dari keharusan menganalisis kode komponen untuk memahami seperti apa komponen ini nantinya.
Untuk bekerja dengan properti, Anda dapat menggunakan
if/else
sederhana:
let result if (variant === 'h1') result = styles.h1 else if (variant === 'h2') result = styles.h2 else if (variant === 'h3') result = styles.h3 else if (variant === 'h4') result = styles.h4 else if (variant === 'h5') result = styles.h5 else if (variant === 'h6') result = styles.h6 else if (variant === 'title') result = styles.title else if (variant === 'subheading') result = styles.subheading
Tetapi kekuatan utama dari pendekatan ini adalah Anda cukup menggunakan desain garis tunggal bersih berikut ini dan mengakhirinya:
const result = styles[variant]
5. Gunakan fungsi panah
Fungsi panah mewakili mekanisme ringkas dan jelas untuk mendeklarasikan fungsi dalam JavaScript (dalam hal ini, akan lebih tepat untuk berbicara tentang keunggulan fungsi panah daripada ekspresi fungsional).
Namun, dalam beberapa kasus, pengembang tidak menggunakan fungsi panah alih-alih ekspresi fungsional. Misalnya, ketika itu perlu untuk mengatur peningkatan fungsi.
Bereaksi menggunakan konsep-konsep ini dengan cara yang sama. Namun, jika seorang programmer tidak tertarik untuk meningkatkan fungsi, maka, menurut pendapat saya, masuk akal untuk menggunakan sintaks fungsi panah:
Perlu dicatat bahwa, menganalisis contoh ini, sulit untuk melihat kekuatan fungsi panah. Keindahan mereka terwujud sepenuhnya dalam desain garis tunggal sederhana:
Saya yakin bahwa desain garis tunggal seperti itu akan menarik bagi semua orang.
6. Tempatkan fungsi independen di luar kait Anda sendiri
Saya telah melihat bagaimana beberapa programmer mendeklarasikan fungsi di dalam kait mereka sendiri, tetapi kait ini tidak terlalu membutuhkan fungsi tersebut. Jenis ini sedikit "mengembang" kode kait dan menyulitkan pembacaannya. Kesulitan dalam membaca kode timbul karena fakta bahwa pembacanya dapat mulai mengajukan pertanyaan tentang apakah kait benar-benar tergantung pada fungsi yang ada di dalamnya. Jika ini bukan masalahnya, lebih baik untuk memindahkan fungsi di luar hook. Ini akan memberikan pembaca kode pemahaman yang jelas tentang apa yang bergantung pada kait dan apa yang tidak.
Berikut ini sebuah contoh:
import React from 'react' const initialState = { initiated: false, images: [], } const reducer = (state, action) => { switch (action.type) { case 'initiated': return { ...state, initiated: true } case 'set-images': return { ...state, images: action.images } default: return state } } const usePhotosList = ({ imagesList = [] }) => { const [state, dispatch] = React.useReducer(reducer, initialState) const removeFalseyImages = (images = []) => images.reduce((acc, img) => (img ? [...acc, img] : acc), []) React.useEffect(() => { const images = removeFalseyImages(imagesList) dispatch({ type: 'initiated' }) dispatch({ type: 'set-images', images }) }, []) return { ...state, } } export default usePhotosList
Jika kita menganalisis kode ini, kita dapat memahami bahwa fungsi
removeFalseyImages
, pada kenyataannya, tidak harus ada di dalam hook, itu tidak berinteraksi dengan keadaannya, yang berarti dapat ditempatkan di luar dan dapat dipanggil dari hook tanpa masalah.
7. Konsisten saat menulis kode
Pendekatan yang konsisten untuk menulis kode adalah sesuatu yang sering direkomendasikan bagi mereka yang memprogram dalam JavaScript.
Dalam kasus React, perlu memperhatikan pendekatan yang konsisten untuk penggunaan desain berikut:
- Impor dan ekspor tim.
- Penamaan komponen, kait, komponen urutan tinggi, kelas.
Saat mengimpor dan mengekspor komponen, saya terkadang menggunakan sesuatu yang mirip dengan yang berikut:
import App from './App' export { default as Breadcrumb } from './Breadcrumb' export default App
Tapi saya juga suka sintaks:
export { default } from './App' export { default as Breadcrumb } from './Breadcrumb'
Apa pun yang dipilih programmer, ia harus menggunakannya secara konsisten dalam setiap proyek yang ia ciptakan. Ini menyederhanakan pekerjaan programmer ini dan membaca kodenya oleh orang lain.
Sangat penting untuk mematuhi konvensi penamaan entitas.
Misalnya, jika seseorang memberi nama hook menggunakan
useApp
, penting bahwa nama hook lain dibuat dengan cara yang sama - menggunakan awalan penggunaan. Misalnya, nama pengait lain dengan pendekatan ini mungkin terlihat seperti
useController
.
Jika Anda tidak mematuhi aturan ini, maka kode proyek, pada akhirnya, bisa berubah menjadi seperti ini:
Beginilah arti dari impor kait ini:
import React from 'react' import useApp from './useApp' import basicController from './basicController' const App = () => { const app = useApp() const controller = basicController() return ( <div> {controller.errors.map((errorMsg) => ( <div>{errorMsg}</div> ))} </div> ) } export default App
Sepintas jelas sekali bahwa
basicController
adalah hook, sama seperti
useApp
. Ini memaksa pengembang untuk membaca kode implementasi dari apa yang dia impor. Ini dilakukan hanya untuk memahami apa sebenarnya yang dihadapi pengembang. Jika kita secara konsisten mematuhi strategi yang sama untuk penamaan entitas, maka situasi seperti itu tidak akan muncul. Sekilas semuanya akan jelas:
const app = useApp() const controller = useBasicController()
Dilanjutkan ...
Pembaca yang budiman! Bagaimana Anda mendekati penamaan entitas dalam proyek Bereaksi Anda?
