Component phần 6: Tổng kết và hệ thống hóa lại về UI Builder, Web Component và React

Fonts, Sizes và Colors

Vì chúng ta sẽ làm việc trực tiếp trên Wordpress + Elemetor nên bước này cả 3 sẽ giống nhau:

  • Vào Site settings và cài đặt Global Colors để dùng cho Elementor

  • Tạo global style trong Custom CSS để dùng CSS variable cho Web Component và React (có thể dùng inspect để check CSS variable của Elementor luôn).

  • Trường hợp design sử dụng font custom, upload file font lên transfronter và copy code về cho vào Custom HTML.

Tạo và lưu component để dùng cho nhiều trang

UI BuilderWeb componentReact Component
Save as TemplateTạo block code khai báo Component và save templateTạo block code khai báo Component và save template
Save as Default

Gọi component ra sử dụng

Đối với Web component và React component, cái phần lưu Template sẽ chỉ là phần khai báo, còn việc gọi ra sẽ thực hiện ở App Logic (tạo 1 block code), lúc này component đã có sẵn ở biến JS.

Với UI Builder thì khác 1 chút vì phần lưu Template sẽ bao gồm cả render luôn, nên có 2 cách xử lý:

  • Sau khi gọi template ra, dùng JS để lưu HTML sau đó xóa block template đó đi.

  • hoặc có thể đặt tag của block Container là <template />, mặc định code trong thẻ này sẽ k hiển thị. Lưu ý: Cái này chỉ được áp dụng sau khi có chỉnh sửa vào plugin elements để cho block Container nhận thêm tag. Cùng xem cách sử dụng của <template />

    Giờ áp dụng vào lại bài lần trước ta sẽ có hướng xử lý gọn gàng hơn chút như sau:

    %[youtube.com/watch?v=3OwSI92m4t4]

    Cái hay của <template /> là nó có thể tự chạy javascript trong thẻ <script />, nên chúng ta không cần phải chạy function rerunHTMLScript nữa.

Quản lý state

  • UI Builder: dùng function useState. state cần được đồng bộ với data attribute.

  • Web component: dùng this.setState. state cũng cần được đồng bộ với data attribute

  • React: dùng useState với React function và this.setState với React class, không cần dùng attribute và có thể dùng props thay thế

Quản lý render

  • UI Builder: đồng bộ giữa data attribute ở parent với giao diện, khi data attribute đổi thì giao diện cũng đổi. set innerHTML dùng template string để chèn state, cẩn thận khi sử dụng innerHTML vì sẽ xuất hiện nháy. Khi bị nháy thì chuyển sang set attribute bằng JS. Loop qua state để render hàng loạt dùng templateEl.content để tạo node và appendChild.

  • Web compoment: cũng set innerHTML dùng template string để chèn state, cũng cẩn thận khi sử dụng innerHTML, nếu bị nháy thì chuyển sang dùng mapStateRender. Loop qua state để render hàng loạt component con thì đơn giản hơn vì chỉ cần chèn thẳng tag của thằng component con vào là đc, không cần dùng <template />.

  • React: return thẳng mã html mà không sợ bị nháy (JSX). loop của state để render hàng loạt component con bằng việc dùng trực tiếp .map từ biến.

Quản lý listener

  • UI Builder: khai báo listener của phần tử bên trong component ở render. thông báo ra bên ngoài bằng cách update attribute event-* . bên ngoài listen bằng onAttributeChange.

  • Web component: cũng khai báo listener của phần tử bên trong ở render. Viết thẳng method vào class và gọi thẳng từ element sau khi đã querySelector. VD: const inputElement = document.querySelector('input-component'); inputElement.onEnter = () => {};

  • React: Viết thẳng trực tiếp trong code JSX. Báo ra ngoài component bằng props. VD: <Input onEnter={() => {}} /> .

Style

  • UI Builder: Dùng trực tiếp UI Builder tạo giao diện, có thể dùng thêm Custom CSS ở tab Advance. Hoặc tạo hẳn 1 block HTML để style thêm bằng code CSS.

  • Web component: viết renderCSSContainer và viết renderStyle để dùng trong render. Luôn ghi nhớ các code CSS bên ngoài component sẽ k tác động đến các phần tử bên trong component.

  • React: có thể đặt className để nhận style bằng class, hoặc viết thẳng style vào qua object style. VD: <div style={{ backgroundColor: 'white' }} />. Lưu ý style này sẽ viết theo kiểu style của JS DOM (camel case). VD: const divEL = document.querySelector('div'); divEL.style.backgroundColor = 'white';.

Cách để các loại giao diện giao tiếp với nhau

Vì bản chất tất cả đều dùng để làm giao diện, nên cuối cùng chúng sẽ đề được render thành các tag HTML. Do đó, cách chung nhất để giao tiếp với nhau là thông qua attribute:

  • dùng getAttribute, setAttribute để đọc, ghi giá trị. với data attribute thì dùng .dataset cho tiện.

  • dùng onAttributeChange để listen thay đổi.

  • các event xảy ra bên trong component cũng nên thông báo thông qua attribute event-*

Với React thì để đồng bộ giữa attribute và state thì chúng ta dùng code sau:

const { useEffect, useState, useRef } = React;

const useAttrState = (initialState, arrayOfDataAttr) => {
    const [state, setState] = useState({});
    const stateRef = useRef(state);
    const getState = () => stateRef.current;

    const elementRef = useRef(null);
    useEffect(() => {
        mapDataAttributeToState(
            elementRef.current,
            getState,
            setState,
            arrayOfDataAttr
        );
    }, []);
    useEffect(() => {
        stateRef.current = state;
    }, [state]);

    return [state, setState, elementRef];
}

const Task = () => {
    const [state, setState, elementRef] = useAttrState({
        text: '',
        important: '0',
        subtask: '0',
        type: 'unfinished',
    }, ['text', 'important', 'subtask', 'type']);
    return (
       <div ref={elementRef}>...</div>
    )
};

Lưu ý:

  • Nếu chỉ giao tiếp giữa các React component với nhau thì k cần dùng đến attribute mà dùng props. props nó như kiểu 1 loại Virtual attribute, sẽ không thể hiện ra tag html

  • attribute phần lớn chỉ nhận dữ liệu là string, trong khi props có thể nhận mọi loại biến JS. có thể nhận cả function (do đó có thể gắn listener trực tiếp vào).

  • đoạn code trên thì chúng ta có thể khai báo useAttrState ở common funcs và dùng đi dùng lại ở nhiều component. Đó được gọi là React hook 1 concept khá phổ biến của React để tái sử dụng logic.