Latest Post

Tăng thứ hạng và truy cập tự nhiên với 10 phương pháp SEO hay nhất Kiếm Tiền Online (mmo): Khái Niệm và Các Hình Thức Phổ Biến

Trong quá trình phát triển phần mềm, chúng ta thường đối mặt với những vấn đề chung mà có thể xuất hiện lặp đi lặp lại trong nhiều dự án khác nhau. Để giải quyết những thách thức này, cũng như để tối ưu hóa quá trình phát triển, chúng ta thường áp dụng các kỹ thuật hay lời giải mà đã được kiểm chứng và đóng góp vào khái niệm được gọi là “pattern” (mẫu).

Một pattern là một mô hình hay một lời giải thường xuyên được sử dụng để giải quyết một vấn đề cụ thể. Trong lĩnh vực lập trình, các pattern thường được tổng hợp từ kinh nghiệm thực tế và được khuyến khích sử dụng để giảm thiểu lỗi và tăng tính tái sử dụng của mã nguồn.

Đối với React, một số pattern phổ biến đã được xác định và khuyến nghị sử dụng. Trong bài viết này, chúng ta sẽ tìm hiểu về những pattern này thông qua các ví dụ cụ thể để hiểu rõ hơn về cách chúng có thể được áp dụng và lợi ích mà chúng mang lại.

Interview react top
Interview react top

Higher-Order Function/Component

Higher-Order functions là một hàm nhận một hàm khác dưới dạng đối số hoặc trả về một hàm dưới dạng đầu ra. Chúng ta có ví dụ dưới đây:

function greaterThan(n) {
  return (m) => m > n;
}

const greaterThan10 = greaterThan(10);

console.log(greaterThan10(11));
// true

Trong ví dụ trước đó, hàm greaterThan được thiết kế để trả về một hàm so sánh giá trị đầu vào với một giá trị xác định trước đó. Cụ thể, với hàm greaterThan10, giá trị xác định là 10. Điều này giúp chúng ta dễ dàng tạo ra các hàm khác nhau bằng cách gọi hàm greaterThan và truyền giá trị cho đối số. Lợi ích chính của việc sử dụng higher-order function được thể hiện thông qua khả năng tái sử dụng và linh hoạt trong việc tạo ra các hàm mới với các điều kiện so sánh khác nhau.

Từ khái niệm trên, trong React chúng ta cũng có khái niệm Higher-Order component (HOC), đó là 1 component mà:

  • Nhận đầu vào 1 component và trả về 1 component mới
  • Biến đổi 1 component thành 1 component khác

 Chúng ta có ví dụ dưới đây:

const withColor = Element => props => <Element {...props} color="red" />

const Button = () => {
  return <button>My Button</button>
}

const ColoredButton = withColor(Button)

Ở đây chúng ta sử dụng HOC withColor để tạo ra component ColoredButton từ component Button với mục đích là set mặc định giá trị màu đỏ cho button đó. 

Thực tế có rất nhiều thư viện sử dụng kỹ thuật này trong React, điển hình như Redux. Để có thể tạo ra những state dùng chung(store) và các action tác động lên toàn bộ component thì Redux tạo ra Provider để bọc toàn bộ các components trong ứng dụng, và đấy cũng chính là 1 HOC.

State Hoisting

Nếu bạn làm việc với React, chắc chắn bạn đã nghe về stateless và stateful components. Đơn giản, stateless component không giữ bất kỳ trạng thái nào, trong khi stateful component giữ trạng thái. Trong một dự án, việc tạo stateless components thường được khuyến khích. Điều này mang lại lợi ích là bạn có thể dễ dàng tái sử dụng chúng hoặc loại bỏ mà không lo lắng về ảnh hưởng đến logic của toàn bộ hệ thống. Hãy xem xét một ví dụ cụ thể dưới đây để hiểu rõ hơn:

<div>
  <CarHeader />
  <CarList />
</div>;

const CarHeader = () => {
  const [cars, setCars] = useState([]);

  useEffect(() => {
    const cars = getData(); //this fuctional function calls an API
    setCars(cars);
  }, []);

  return <div> No of Cars: {cars.length}</div>;
};

const CarList = () => {
  const [cars, setCars] = useState([]);

  useEffect(() => {
    const cars = getData(); //this fuctional function calls an API
    setCars(cars);
  }, []);

  return (
    <>
      {cars.map((car) => (
        <div>Car:{car.name}</div>
      ))}
    </>
  );
};

2 components CarHeader và CarList đều sử dụng cùng dữ liệu là danh sách car lấy từ API trả về, cách tốt hơn ở đây là sẽ khai báo state cars ở trong component cha, loại bỏ biến state trong 2 component con để biến chúng thành các stateless component.

useEffect(() => {
  const cars = getData(); //this fuctional function calls an API
  setCars(cars);
}, []);

return (
  <div>
    <CarHeader cars />
    <CarList cars />
  </div>
);

Kỹ thuật này gọi là state hoisting, ngoài việc tạo ra các staless component con, thì lúc này dữ liệu cũng được lấy từ 1 nguồn duy nhất (single source of truth) giúp các component đồng bộ với nhau, việc debug ứng dụng cũng trở nên dễ dàng hơn.

Ngoài việc đẩy data ra component cha để xử lý, thì chúng ta cũng sử dụng kỹ thuật này vơi các events trong các phần tử con có tương tác với người dùng, ví dụ như các thẻ Input.

const Name = ({ onChange }) => (
  <input onChange={(e) => onChange(e.target.value)} />
);

const NameContainer = () => {
  const [name, setName] = useState("");

  return (
    <>
      <div>Your name: ${name}</div>
      <Name onChange={(newName) => setName(newName)} />
    </>
  );
};

Trong ví dụ trên, thẻ input tạo ra trong component Name và chúng ta muốn lấy được dữ liệu ra trong component cha của nó, không tác động thêm state vào Name, cách giải quyết là đẩy event onChange ra ngoài để component cha (NameContainer) sử dụng, vẫn đảm bảo được tính “stateless” của Name.

Proxy Component

Proxy pattern là 1 thiết kế mẫu giúp bạn kiểm soát truy cập đến đối tượng ban đầu, giúp bạn hạn chế việc sai sót trong quá trình tái sử dụng component ban đầu cũng như tạo ra 1 component mới.

Ví dụ chúng ta có 1 component button được sử dụng trong App như sau:

<button type="button">
</button>

// button type
// 1. button
// 2. reset
// 3. submit

Nếu chúng ta trực tiếp sử dụng thẻ button trong ứng dụng và luôn phải khai báo type cho nó, một vấn đề nảy sinh là nếu ta muốn hạn chế việc sử dụng type=submit. Làm thế nào chúng ta có thể giải quyết vấn đề này? Một cách là tạo một component mới với thuộc tính type=button để đảm bảo mọi button được tạo ra đều có cùng thuộc tính type. Công nghệ này được gọi là Proxy, giúp đảm bảo tính nhất quán trong thuộc tính của component và đồng thời giới hạn việc truy cập đến các thuộc tính khác trong component gốc.

const Button = (props) => {
  return <button type="button" {...props}></button>;
};

return (
  <>
    <Button />
    <Button className="CTA">Send Money</Button>
  </>
);

Chúng ta cũng có thể sử dụng kỹ thuật này cho các thuộc tính của style để tạo ra các Style component. 

import classnames from "classnames";

const PrimaryBtn = (props) => <Btn {...props} primary />;

const Btn = ({ className, primary, ...props }) => (
  <button
    type="button"
    className={classnames("btn", primary && "btn-primary", className)}
    {...props}
  />
);

<button type="button" className="btn btn-primary"></button>;

3 cách khai báo code trên sẽ cùng cho ra 1 kết quả giống nhau, trong trường hợp này PrimaryBtn component được sử dụng như 1 Proxy cho component button với cách khai báo gọn và thống nhất hơn.

(Công cụ code online: Simple Online Code Editor)

Kết bài

Dưới đây là ba mô hình thường xuyên xuất hiện và được sử dụng trong lập trình React. Việc áp dụng đúng và hợp lý các mô hình này không chỉ làm cho mã nguồn của bạn trở nên rõ ràng và giảm thiểu rủi ro lỗi, mà còn giúp bạn phát triển kỹ năng lập trình của mình. Hy vọng rằng bài viết này mang lại giá trị cho bạn. Chúng ta sẽ gặp lại trong những bài viết tiếp theo với nhiều thông tin hữu ích khác.

Tác giả: Phạm Anh Khoa

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *