https://embed.notionlytics.com/wt/ZXlKd1lXZGxTV1FpT2lJMVlUSXhZamsxTUdVMVlqazBNVGN4T1RSbVpESTVabU0xTkRRMk5qVXdZeUlzSW5kdmNtdHpjR0ZqWlZSeVlXTnJaWEpKWkNJNklraERPRGx5ZWxkNlZrRm5Wbk40YWpobmFuWk9JbjA9

Mở đầu

Trong bài viết này chúng ta sẽ cùng nhau xây dựng một thư viện để phát triển UI giống như React.

Mục tiêu của chúng ta là cung cấp ra một thư viện có thể render các functional Component, với các hook. Thông qua việc xây dựng thư viện này, chúng ta có thể hiểu thêm về cách mà React render một Component, cũng như cách các hooks của React hoạt động.

Ở giai đoạn đầu tiên, chúng ta tập trung vào việc cung cấp ra 3 APIs có signature giống với React, mà chưa quan tâm tới performance của các API này. Việc cải thiện performance sẽ được mô tả ở các bài viết tiếp theo. Cụ thể trong bài viết lần này, chúng ta sẽ implement một thư viện với thuật toán Stack Reconciliation.

Thư viện của chúng ta sẽ cung cấp ra 3 APIs chính

// API giống với React.render 
function render(vnode, container);

// API giống với API React.useState 
function useState(initialValue);

// API giống với API React.useEffect
function useEffect(callback, args);

Thư viện có thể được sử dụng như sau

function App() {
  const [count, setCount] = useState(0);
  const increase = () => setCount(count + 1);
  const decrease = () => setCount(count - 1);
  
  return (
    <div>
      <button onClick={increase}>inc</button>
      {count}
      <button onClick={decrease}>dec</button>
    </div>
  );
}

render(<App />, document.getElementById("app"));

Sau đoạn code kể chúng, chúng ta sẽ render component App vào một DOM node có id là app

1. JSX và VNode

1.1. Virtual DOM

Vậy làm thế nào mà React có thể render một component được định nghĩa từ JSX thành một DOM Element?

Khi developers định nghĩa một Component bằng JSX như <Component prop="value" />, ở bên dưới thông qua Babel Compiler, đoạn code này sẽ được biến đổi thành hàm như sau

React.createElement(Component, {
  prop: "value"
})

Hàm này được gọi là hàm createElement , hàm trả về một Virtual Node (từ đây về sau chúng ta sẽ gọi tắt là VNode). Thay vì tương tác trực tiếp với DOM Element, các thư viện như React / Vue tạo ra các VNode, và để developers tương tác (tạo mới / update các thuộc tính / xoá) các VNode này, sau đó các thư viện mới biến đổi các hoạt động của developers thành hoạt động tương ứng với DOM Element. Mục đích của việc này nhằm để giảm thiểu các hoạt động thay đổi DOM Element, từ đó tăng hiệu năng của ứng dụng.

Mặc định Babel sẽ sử dụng hàm React.createElement để translate các JSX component thành các JS function. Tuy nhiên, chúng ta có thể thay đổi cấu hình này bằng cách, trong một đoạn code bất kỳ, add thêm comment như sau

// @jsx h 

Thông qua comment ở trên, chúng ta báo cho Babel rằng, thay vì sử dụng hàm React.createElement, để code trở nên ngắn gọn, từ đây về sau chúng ta sử dụng hàm h để thay thế cho hàm React.createElement . hlà viết tắt của hyperscript