Giới thiệu cơ bản về Styled components

Giới thiệu cơ bản về Styled components

1. Styled components là gì?

1.1. Phương pháp css truyền thống

Trước khi nói về styled components chúng ta phải nói về phương pháp truyền thống khi tiếp cận đến việc làm đẹp cho một trang web. Thông thường việc này sẽ được thực hiện theo những bước sau:

  • Xây dựng các thành phần HTML
<div class="content">
  <span>This is a span</span>
</div>
  • Dùng các selector (className, id, element name) để làm đẹp những element này trong một file css riêng
.content {
  background-color: #000;
}

.content > span {
  color: #fff;
}

Đây là cách tiếp cận truyền thống đối nhưng nó lại không hoàn toàn phù hợp cho việc viết React vì những nhược điểm sau:

  • Các class, id trong css được dùng chung cho cả trang web dẫn đến việc conflict khi đặt tên cho class, id (có thể được giải quyết bằng naming convention như BEM, hay với Webpack css module)
  • Việc thay đổi style, animation dựa trên đầu vào và trạng thái của element khá rắc rối và không tự nhiên
  • Việc đặt css ở một file riêng thường được cho là best practice cho seperation of concerns nhưng sự tách biệt giữa css và html hay js không thực sự là seperation of concerns mà là seperation of Technologies. Trích từ You're Missing The Point Of JSX

1.2. Into Styled Components

alt text Với Styled Components thay vì sử dụng những selector để làm đẹp cho element như trên chúng ta sẽ định nghĩa những components với style chỉ dành riêng cho bản thân nó. Sau đây sẽ là component trên viết lại bằng styled components:

// chúng ta tạo một styled div component bằng cách sau
// Note: styled.div chỉ là một function bình thường
//       việc gọi function với dấu `` là một tính năng của es6
//       func`abc` sẽ tương đương với func(['abc'])
//       func`abc ${variable} def` sẽ tương đương với func(['abc ', ' def'], variable)
const MyComponent = styled.div`
  background-color: #000;

  > span {
    color: #fff;
  }
`;

export default () => (
  <MyComponent>
    <span>This is a span</span>
  </MyComponent>
);

hoặc cách thứ 2 mà mình thích hơn

// component phải nhận props className để có thể dùng theo cách này
const MyComponent = ({ className }) => (
  <div className={className}>
    <span>This is a span</span>
  </div>
);

const MyStyledComponent = styled(MyComponent)`
  background-color: #000;

  > span {
    color: #fff;
  }
`;

export default MyStyledComponent;

2. Lợi ích của Styled Components

2.1. Encapsulate (đóng gói) style vào trong component trong js

Styled component cho phép chúng ta encapsulate (đóng gói) style vào trong component trong js nhưng vẫn giữ được những tính năng của css như nesting, media query, pseudo-selectors, v.v. Điều này giải quyết vấn đề global scope của css bởi vì chúng ta không còn phải viết các selector cho class hay id. Styled component làm được điều này nhờ việc generate tên class ngẫu nhiên và truyền vào component thông qua property className như có thể thấy ở ví dụ trên.

alt text

Tên class ngẫu nhiên ở runtime

Thêm vào đó styled component còn thực hiện việc auto-prefixing như sass để hỗ trợ những tính năng mới như `flexbox` cho những trình duyệt cũ hơn

alt text

css được inject ở runtime

2.2. Thay đổi style dựa trên thuộc tính hoặc trạng thái của component dễ dàng hơn

Mình sẽ thể hiện lợi ích này thông qua các ví dụ sau: Trường hợp 1: Chúng ta có một button có 2 trạng thái bình thường và disable. Thông thường chúng ta sẽ viết như sau:

// js
const Button = ({ disable }) => (
  <button disable className={'btn' + (disable ? ' disable' : '')}  />
);
/* css */
.btn {
  background: palevioletred;
  color: white;
  /* ... */
}

.disable {
  background: white;
  color: gray;
}

với styled component nó sẽ trở thành

const Button = styled.button.attrs({
  // pass property tới component thông qua hàm .attrs
  disable: props => props.disable
})`
  /* Thuộc tính css được tính dynamically dựa trên thuộc tính của component */
  background: ${props => props.disable ? 'palevioletred' : 'white'};
  color: ${props => props.disable ? 'white' : 'gray'};
  /* ... */
`;

Trường hợp 2: Set background, border-radius của component bằng property của component. Với css thông thường việc này chỉ có thể được làm bằng cách set property style trên element (Mình có thể sai chỗ này 😆). Nhưng có thể làm dễ dàng với styled-components.

const Frame = styled.div`
  // truyền biến vào css
  background: ${props => props.background};
  border-radius: ${props => props.borderRadius};
  /* ... */
`;

3. Một số nhược điểm và hạn chế

  • Tên class được generate ngẫu nhiên nên sẽ gây khó chịu cho người quen debug css bằng tên class.
  • Còn khá non trẻ nên chưa được kiểm duyệt tính scale trong các project lớn
  • Nhiều người vẫn không thích css trong js
  • Có thể không hoạt động tốt với css có sẵn dù mình chưa gặp vấn đề này bao giờ.
  • Không được dùngref trên component phải chuyển sang innerRefbởi vì ref sẽ được truyền vào wrapper của styled component thay vì component mình muốn.

Link bài viết gốc của mình

All Rights Reserved