title | sidebar_label |
---|---|
JavaScript/React |
JavaScript/React |
Sau đây là quy ước code JavaScript chung của team, áp dụng chủ yếu cho phía Frontend / Mobile React Native.
- Chỉ sử dụng phiên bản Node LTS mới nhất (hiện là 14). Nếu sử dụng nvm thì lện cài đặt là:
npm install --lts
- Cài đặt
node-gyp
dạng global package.
Tên biến component phải là dạng camelCase
// OK
import reservationCard from './ReservationCard';
// Sai
import ReservationCard from './ReservationCard';
// OK
const reservationItem = <ReservationCard />;
// Sai
const ReservationItem = <ReservationCard />;
Có 2 cách sắp xếp:
Cách này khá cơ bản, đơn giản nhưng đủ chức năng, cấu trúc cây thư mục trông như sau:
├── datasource
├── assets
│ ├── fonts
│ ├── icons
│ ├── images
│ └── styles
├── common
├── components
│ ├── button
│ ├── header
│ │ ├── header-button
│ │ └── searchbox
│ ├── logo
│ └── swtich
├── redux
├── routes
│ ├── authen
│ │ ├── products
│ │ ├── purchase-request
│ │ └── successful
│ └── guest
│ └── login
│ └── login-form
├── stores
└── utils
Dù có thể Redux sẽ không được áp dụng, nhưng vì độ phổ biến của nó và hệ thống tài liệu xuất sắc, cây thư mục trên vẫn có tên Redux.
-
redux
: Chứa các module sử dụng cho redux, bao gồm fileredux-instance.ts
để ở ngoài làm file config và 1 thư mục tênfeatures
bên trong để đưa logic, slices củaredux-toolkit
vào, bên trong cũng cótypes.js
để chứa các Type của action (có export ra). -
datasource
: Chứa các file liên quan đến việc gọi web api. File gốc sẽ làapi.js
hoặcapi.ts
, tất cả các interceptor sẽ được đặt cùng folder. Nguồn lấy data có thể là từ remote hoặc local (từ server ngoài hoặc từ sqlite trong máy tính, localstorage,...). -
assets
: Chứa các resource file như ảnh, icon,... -
common
: Chứa các file utils để tái sử dụng nhiều lần, file dịch đa ngôn ngữ, file tổng hợp màu sắc, và các config được định nghĩa sẵn.
Thứ tự import sẽ là:
- React / first party lib
- Các lib bên thứ 3
- Các file tự viết, trong đó cũng theo thứ tự:
- Component
- Utils
- Redux / State management
- Typing (TypeScript)
- CSS
require
(nếu phải dùng)
Nếu dùng babel 6 đổ về trước hoặc có dùng module import từ React).
Đúng:
:::tip Đúng
import React, {useEffect} from 'react';
import {StatusBar, LogBox, AppState} from 'react-native';
import {Provider} from 'react-redux';
...
:::
:::danger Sai
import {Provider} from 'react-redux';
import React, {useEffect} from 'react';
...
:::tip Đúng
Một số framework cho phép ta config babel / webpack để có thể import dạng absolute lấy theo alias của project. Do đó ta có thể import theo kiểu:
import {store, persistor} from '~/redux/redux-instance';
import {AppNavigator} from '~/navigations/stack-navigator';
Dấu alias luôn lấy là ~
hoặc @
tuỳ dự án.
Ví dụ, module static-data
chỉ chứa các biến constant, các giá trị tĩnh. Không chứa logic tính toán ngoài:
:::tip Đúng
export const PackageTypes = {
FLEXIBLE: 0,
COMPREHENSIVE: 1,
OVERSEE: 2,
};
export const PlaceTypes = {
ONLINE: 0,
OFFLINE: 1,
};
export const MaterialType = {
QUIZ: 11,
SLIDE: 10,
};
:::
:::danger Sai
export const PackageTypes = {
FLEXIBLE: 0,
COMPREHENSIVE: 1,
OVERSEE: 2,
};
export const PlaceTypes = {
ONLINE: 0,
OFFLINE: 1,
};
export functiion getNoteExpandedSheetHeight {
return (
WINDOW_HEIGHT - // Size tổng
getStatusBarHeight() -
VRM_ROOM_HEADER_HEIGHT -
(Platform.OS === 'ios' ? BOTTOMSHEET_HANDLE_HEIGHT : -2)
);
}
:::
Nhằm tránh các tác dụng phụ, các closure ngoài ý muốn trong JavaScript / TypeScript. Ta chỉ sử dụng let và const. let
khi ta cần assign lại biến về sau và const khi biến đó không cần assign.
:::tip Đúng
const a = 1;
let b = 'test';
b = 'test 2';
:::
:::danger Sai
var a = 1;
:::
Với những component có đặc điểm chung về hành vi nhưng khác về giao diện, có 2 kĩ thuật phổ biến với React là:
Tiêu biểu là component connect
mà ta vẫn thường dùng với Redux. Ta hoàn toàn có thể làm một component tương tự.
function logProps(WrappedComponent) {
return class extends React.Component {
componentDidUpdate(prevProps) {
console.log('Current props: ', this.props);
console.log('Previous props: ', prevProps);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
}
Là kĩ thuật chia sẻ code giữa các component React sử dụng prop mà value của nó là function (hay còn gọi là "function as a child"):
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
DRY có nghĩa là __D__on't __R__epeat __Y__ourself - đừng lặp lại. Mục đích của việc lập trình là không làm lặp lại những gì máy có thể làm được. Do đó ta cũng cần tránh lặp lại code, copy paste vô tội vạ.
Ví dụ để lặp lại một component 5 lần thì thay vì:
<View>
<ComponentDemo>
<ComponentDemo>
<ComponentDemo>
<ComponentDemo>
<ComponentDemo>
</View>
Ta viết:
<View>
{[0, 1, 2, 3, 4].map(() => <ComponentDemo>)}
</View>
Hoặc tuỳ ngữ cảnh, cũng có thể viết:
// (N) là số phần tử
<View>
{Array(N).fill().map(() => <ComponentDemo>)}
</View>
async
và await
đã có từ ES6 và đã hỗ trợ rất tốt các framework hiện nay. Ưu tiên sử dụng do cách viết gần với luồng code bình thường và có thể viết unit test dễ dàng hơn.
Việc dùng các kí tự đặc biệt sẽ gây khó khăn cho thao tác đọc / ghi và xử lý JSON về sau. Bao gồm:
- Kí tự đặc biệt như:
!@#$%^&*()
- Số (trừ một số trường hợp đặc biệt)
- Các từ nằm trong từ khoá của ngôn ngữ lập trình:
class
,default
,get
,set
Đúng:
{
"color": "green"
}
Sai:
{
"$%%@&^": "green"
}
:::tip Đúng
import React from "react";
import CssColors from "~/assets/styles/_colors.module.scss";
import { EventBus } from "~/helpers/event-bus";
import "~/components/color-picker/color-picker.scss";
...
:::
:::danger Sai
import React from "react";
import "~/components/color-picker/color-picker.scss";
import CssColors from "~/assets/styles/_colors.module.scss";
import { EventBus } from "~/helpers/event-bus";
...
:::
$color-black-primary: #131416;
@import "./_colors.scss";
:export {
colorBlackPrimary: $color-black-primary;
}
Sau đó có thể sử dụng:
import React from "react";
import { EventBus } from "~/helpers/event-bus";
import CssColors from "~/assets/styles/_colors.module.scss";
import "~/components/color-picker/color-picker.scss";
const COLOR_SEED = [
CssColors.colorBlackPrimary,
CssColors.colorGrassGreen,
CssColors.colorRed,
CssColors.colorWhite,
];
export const ColorPicker: React.FC = () => {
return (
<div className="color-picker">
{COLOR_SEED.map((n, id) => (
<div
className="orb"
style={{ backgroundColor: n }}
key={id}
onClick={() => EventBus.emit("changeColor", { color: n })}
/>
))}
</div>
);
};