# Đi sâu vào công nghệ Component: Custom Component & Multiple Platforms

Sau khi cưỡi ngựa xem hoa 1 vòng các bài  [trước](https://lequanghuylc.com/series/gioi-thieu-ve-lap-trinh)  thì đến giờ chúng ta đã có thể làm 1 cái web, hoặc 1 cái app. Mặc dù rất đơn giản thôi nhưng nó sẽ là cánh cổng để mở đến những hệ thống phức tạp hơn. Bài này sẽ đi sâu thêm chút nữa về công nghệ Component vì nó khá quan trọng với Frontend development

## Nhìn lại một chút của bài trước:
1. `HTML`, `CSS`, `Javascript` là nền tảng của Frontend Web. 
2. `URP` thực chất là `React Native`, là một thư viện dùng để code cho mobile app như `android` và `iOS`. Bình thường để code `android` chúng ta cần dùng `Java` (cái này khác `Javascript` nhé) hoặc `Kotlin`, code `iOS` thì dùng `Objectice C` hoặc `Swift`. `React Native` sinh ra là để giúp chúng ta có thể code chỉ bằng `Javascript` và build ra được app cho cả 2 nền tảng `Android` và `iOS`. `URP` là viết tắt của `Universal React Practice` là việc dùng `React Native` để code cả cho nền tảng web. Giải pháp code đa nền tảng được gọi là `cross platform`.
3. Bạn sẽ thấy được sự giao thoa giữa ý 1 và ý 2 là `Javascript`. Đúng vậy cái này sẽ là ngôn ngữ chủ yếu của toàn bộ series. Ban đầu học cách build giao diện thì chưa cần để ý nhiều nhưng hãy để tâm đến nó
4. Component sẽ có hình dạng kiểu như này `<Component></Component>` hoặc `<Component />`

## Hướng học Component với Multiple Platforms

Về mặt giao diện, chúng ta sẽ học song song `URP` và `HTML`, mục đích để cho bạn nắm được nhiều cách thức làm giao diện nhất có thể, học bằng nhiều cách sẽ giúp hiểu bản chất nhanh hơn, ngoài ra có thể làm được nhiều job hơn sau này.

Ảnh dưới đây là giới thiệu một số Component quan trọng mà chắc chắn bạn cần nhuyền nhuẫn


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642410735562/WSWjes7Od.png)

Chúng ta sẽ bắt đầu từ những Component nhỏ và build nó dần dần to lên. Cái quan trọng là cần nắm vững bản chất. 1 điểm cần lưu ý với Multiple Platforms đó là mỗi Platform sẽ đều có những điểm riêng và cần lưu ý. Cụ thể cần nắm 2 điểm quan trọng đầu tiên như sau:

- `URP` Component style lấy cảm hứng từ `CSS` tuy nhiên nó chỉ là 1 tập con của `CSS`, nhiều style áp dụng được cho `HTML` sẽ không áp dụng được cho `URP` component. Vì thế, chúng ta cần sử dụng 1 hướng style chung có thể sử dụng cho cả 2.

- Có 2 thuộc tính style quan trọng là `position` và `display`.
- - **position**: Với `HTML` thì có rất nhiều `static` (mặc định), `fixed`, `sticky`, `relative` và `absolute`. Nhưng với `URP` chỉ có thể dùng `relative` (mặc định) và `absolute`. 
- - **display**: với `HTML` thì có `inline` & `block` (mặc định), `flex`, `none` và 1 số khác. Nhưng với `URP` thì chỉ có `flex`, `none`. Cái này sẽ liên quan đến việc thiết lập các layout cho component, vì với HTML có 3 hướng làm layout trọng tâm là dự theo `block`, dựa theo `flex` và dựa theo `grid`, để đảm bao cho style chạy trên cả 2 nền tảng, chúng ta sẽ học và sử dụng theo hướng `flex`

### Bài tập 1: Hoàn thành khóa học CSS Flexbox trên Freecodecamp

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642413386015/nBhUzgXCd.png)

và đọc bài viết này:

https://reactnative.dev/docs/flexbox

## Bắt tay làm thử 1 số Component nhỏ

Component thường được chia làm 2 loại là Container và Item. Item là các mục nội dung chính (Content) của trang web/app và Container là dùng để chứa các Item. Container sẽ chuyên về phân phối bố cục (Layout) còn Item sẽ chuyên về trang trí sao cho hợp lý, dễ nhìn (Decoration). Thường thì khi nhìn vào 1 trang web/app cái mà thu hút mắt nhìn chính là Item.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642474728850/dUD1DbVPAD.png)


Một page có thể có nhiều item và nhiều container.

Chúng ta thử bắt đầu làm 1 cái Container trước như này:


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642475210528/_6R1KPmUA.png)

### Khai báo custom Component với URP

Bước 1: Mở https://snack.expo.dev/ và lại xóa hết code có sẵn

Bước 2: Viết lên bên trên 1 Custom Component mẫu như này:

```jsx
const CustomComponent = ({ children }) => (
  <View>
    {children}
  </View>
);
```


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642475484519/toSlLis9o.png)

Tạm thời bạn chỉ cần hiểu là `children` sẽ là các Component cấp con của nó, nằm bên trong đó, còn cú pháp khai báo thì cứ học thuộc đã.

Để hiển thị thì nhét vào trong đoạn Component ở chỗ `export default`, phải để vào bên trong đó thì mới hiển thị được.

```jsx
export default () => {
  return (
    <View>
      <CustomComponent>
        <Text>Xin chào các bạn</Text>
      </CustomComponent>
    </View>
  );
}
```


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642475738582/fzJFTZNzA.png)

Giờ cần làm cho `children` ra giữa, và thêm thuộc tính chiều cao cho Component

```jsx
const Middle = ({ children, height }) => (
  <View
    style={{
      width: '100%',
      height: height,
      justifyContent: 'center',
      alignItems: 'center',
    }}
  >
    {children}
  </View>
);

export default () => {
  return (
    <View>
      <CustomComponent>
        <Text>Xin chào các bạn</Text>
      </CustomComponent>
      <Middle height={50}>
        <Text>Đây là component Middle</Text>
      </Middle>
    </View>
  );
}
```

Vậy là xong component, nhìn vào preview bạn sẽ thấy nó đã hiển thị ở giữa


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642476084311/ZecavUjKX.png)

Chỗ này có 1 vài lưu ý, hãy nhìn những chỗ khoanh đỏ để nắm được sơ lược về:
- Cách truyền thông tin `height={50}` đến đoạn set `height: height`
- `children` chính là Component bên trong, k cần truyền `chilren={...} giống height`

Để cho rõ hơn, hãy tạo border đứt đoạn để nhìn đc phạm vi của container


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642476260399/rlV2G3pT-.png)

Okay như vậy là xong <Middle /> ở `URP`, chuyển sang làm với `HTML`

### Khai báo custom Component với HTML

Bước 1: Mở https://codepen.io/ và tạo 1 pen mới

Ở ô `JS` điền vào đoạn code như sau để khai báo component:

```javascript
class MiddleComponent extends HTMLElement {
    defaultStyle = `
      div {
        display: flex;
        flex-direction: column;
        align-content: flex-start;
        flex-shrink: 0;
        position: relative;
      }
    `;
    constructor() {
        super();
        this.shadow = this.attachShadow({ mode: "open" });
        this.shadow.innerHTML = `
          <style>
            ${this.defaultStyle}
            div {
              width: 100%;
              justify-content: center;
              align-items: center;
              border-width: 1px;
              border-style: dashed;
              border-color: lightgrey;
            }
          </style>
          <div><slot></slot></div>
        `;
    }
}
customElements.define("middle-component", MiddleComponent);
```
Sau đó điền vào ô `HTML` như sau:
```html
<middle-component>
  <span>Đây là component Middle</span>
</middle-component>
```
Chúng ta sẽ được kết quả:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642477620715/hJBNvoBFh.png)

1 số lưu ý:
- code sử dụng chủ yếu là `Javascript` nên hãy chú ý cú pháp của nó. Các nội dung HTML và CSS sẽ được để trong `string` của `Javascript`
- đoạn `defaultStyle` là chúng ta thay đổi các thuộc tính style mặc định của `div`, nên nhớ với `HTML` thì `display` mặc định là `block` và `position` mặc định là `static`. Dùng `defaultStyle` để cho giống với `URP`
- `<slot></slot>` sẽ đóng vai trò giống như `{children}` ở bên `URP`
- với `HTML` thì chỉ đặt được tên component theo dạng  [kebab-case](https://en.wiktionary.org/wiki/kebab_case) , nên đặt tên component gồm 2 chữ, nếu lúc code thấy không hiện component của mình thì nên check lại xem đặt tên đã đúng chưa

Giờ chúng ta sẽ thêm như sau để nhận thuộc tính `height`

```javascript
constructor() {
        super();
        this.shadow = this.attachShadow({ mode: "open" });
        const height = this.getAttribute("height") || "auto";
        this.shadow.innerHTML = `
          <style>
            ${this.defaultStyle}
            div {
              width: 100%;
              height: ${height};
              justify-content: center;
              align-items: center;
              border-width: 1px;
              border-style: dashed;
              border-color: lightgrey;
            }
          </style>
          <div><slot></slot></div>
        `;
    }
```


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642478441653/rCOCdMcOC.png)

OKay vậy là xong r đó `<Middle />` cho `URP` và `<middle-component></middle-component>` cho `HTML`

### Bài tập 2: 

Code lại giao diện này


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642478790730/JlL-zu6Fr.png)

Yêu cầu:
- Code thành 2 component, 1 container và 1 item. Như vậy nó sẽ có dạng như này:

```
<Container>
  <Item />
  <Item />
  <Item />
</Container>
```

- Phải code trên cả `URP` và `HTML`, gửi lại link snack và link codepen

Lưu ý: Giao diện Web preview của snack hơi nhỏ có thể mở sang của sổ preview to hơn để code. 
