Dependency injection trong React với JSX và context

Dependency injection trong React với JSX và context

Dependency injection là một dạng design pattern phổ biến được áp dụng vào để cố gắng đạt được sự không phụ thuộc giữa các object với nhau làm cho code clean hơn, dễ đọc và dễ test. Nó cũng được tích hợp sẵn trong nhiều framework lập trình như Angular, Symfony, Spring,…

Các dạng dependency injection

  • Constructor injection: là dạng được sử dụng phổ biến nhất, bằng cách truyền các dependency vào 1 class thông qua constructor của class đó.
  • Setter injection: đối với dạng này thì các dependency sẽ được truyền vào 1 class thông qua các hàm Setter của class đó.
  • Interface injection: để thực hiện ta cần phải tạo ra 1 interface chứa 1 hàm Inject và class cần injection sẽ implement interface này. Container sẽ truyền dependency vào 1 class bằng cách gọi hàm Inject của interface đó.

Dependency injection trong React JS

Thẳng thắng mà nói thì trong React không có dependency injection container như trong Angular hay một số famework có tích hợp sẵn design pattern này. Tuy nhiên khi sử dụng React chúng ta hoàn toàn có thể thực thi các dependency injection một cách dễ dàng thông qua JSX và context có sẵn trong React mà không cần đến dependency injection container.

JSX trong React cho phép chúng ta di chuyển, thay thế linh động các dependency cũng như cấu hình chúng thông qua việc chia tách các components và truyền vào nhau thông qua props.

Ngoài ra để thuận tiện hơn trong việc truyền qua nhiều lớp components nested hay nói cách khác để tránh wrapper hell thì React cung cấp thêm cho chúng ta một công cụ nữa đó là context. Dưới đây là một ví dụ về việc sử dụng context để tạo ra một service component xác thực người dùng:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { createContext, useContext, useState, useEffect } from "react";

interface Auth {
isAuthenticated: boolean;
setToken: (token: string) => void;
clearToken: () => void;
}
const AuthContext = createContext({} as Auth);

export const AuthProvider = ({ children }) => {
const [logined, setLogined] = useState(true);

useEffect(() => {
const token = localStorage.getItem("token");
if (!token) {
setLogined(false);
} else {
redirectAfterLogin();
}
}, []);

const setToken = async (token: string) => {
await localStorage.setItem("token", token);
setLogined(true);
redirectAfterLogin();
};

const clearToken = async () => {
await localStorage.removeItem("token");
setLogined(false);
redirectAfterLogout();
};

const redirectAfterLogin = () => {
window.location.href = "/home";
};

const redirectAfterLogout = () => {
window.location.href = "/login";
};

return (
<AuthContext.Provider
value={{ setToken, clearToken, isAuthenticated: logined }}
>
{children}
</AuthContext.Provider>
);
}

Trong đoạn code trên mình có sử dụng một tính năng mới được React thêm vào từ phiên bản React 16.8 đó là React Hook. Vì vậy ở ví dụ trên chúng ta có thể định nghĩa ra các hook để tiện sử dụng ở các component khác hơn:

1
2
3
4
export const useAuth = () => {
const authContext: Auth = useContext(AuthContext);
return authContext;
};

Chúng ta có thể wrap application lại bằng AuthProvider và handle các components dựa trên trạng thái đăng nhập của user như hàm bên dưới.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export function ProtectRoute(Component) {
return () => {
const { isAuthenticated } = useAuth();
const pathName = window.location.pathname;
useEffect(() => {
if (!isAuthenticated) {
window.location.href = "/login";
} else if (
isAuthenticated &&
(pathName === "/" || pathName === "/login")
) {
window.location.href = "/home";
}
}, [isAuthenticated]);

return <Component />;
};
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×