Hãy xem xét một ứng dụng web tương tác đơn giản bao gồm một thanh trượt. Khi chúng tôi di chuyển thanh trượt, chúng tôi muốn một số phần tử HTML tự động di chuyển xung quanh. Điều này có nghĩa là chúng ta phải tìm các nút có liên quan trong DOM và thiết lập trình xử lý sự kiện và cập nhật DOM bất cứ khi nào trạng thái thay đổi
Move me:
drag the slider to move me
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
[jsfiddle trực tiếp]
Điều này hoạt động tốt cho ví dụ đơn giản này, nhưng thực sự không mở rộng quy mô tốt. Khi nhiều yếu tố tương tác được thêm vào một trang, rất khó để giữ cho tất cả các luồng dữ liệu rõ ràng và đơn giản, không có xung đột về tên, v.v.
Giao diện người dùng phản ứng
Các phương pháp để khắc phục sự phức tạp của GUI cũ hơn so với web, ví dụ như với mẫu Model–View–Controller
Điều mà React và các khung công tác giao diện người dùng tương tự như Vue làm là cung cấp một con đường để giải quyết sự phức tạp này, ẩn đi tất cả các bit phức tạp. Ý tưởng chung là
- ứng dụng có một số trạng thái hiện tại,
- DOM phải luôn phản ánh trạng thái hiện tại và
- để thay đổi DOM, thay vào đó bạn thay đổi trạng thái hiện tại
Đây là lập trình phản ứng, bởi vì đầu ra [DOM] luôn tự cập nhật khi đầu vào/phụ thuộc [trạng thái] của nó bị thay đổi
Điều này có nghĩa là lập trình viên không phải suy nghĩ về tất cả các luồng dữ liệu DOM × DOM mà có thể tập trung vào việc quản lý trạng thái và cách hiển thị trạng thái trong DOM hiện tại
Việc triển khai ngây thơ của phương pháp này sẽ hiển thị lại toàn bộ trang/thành phần bất cứ khi nào bất kỳ phần nào của trạng thái thay đổi
Move me:
const app = document.getElementById["app"];
const slider = document.getElementById["slider"];
const renderSlidingText = [pos] => app.innerHTML = `
drag the slider to move me
`;
slider.addEventListener['input', ev => renderSlidingText[ev.target.value]];
renderSlidingText[slider.value] // render initial state
[jsfiddle trực tiếp]
Điều đó hầu như hoạt động tốt đối với ví dụ nhỏ này, nhưng việc thay thế các phần lớn hơn của DOM sẽ làm giảm hiệu suất đáng kể [việc bố trí trang rất tốn kém cho trình duyệt]. Vì vậy, những gì các khung này làm là tránh sử dụng
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
2, thay vào đó hãy tự phân tích cú pháp mẫu và sau đó so sánh DOM mong muốn với DOM hiện tại để áp dụng nhiều bản cập nhật phẫu thuật hơn. Ví dụ: React có thể sẽ thấy ở đây chỉ cần cập nhật thuộc tính kiểu CSS mà không phải thay thế toàn bộ phần tửThành phần giao diện người dùng
Ngoài việc hỗ trợ lập trình phản ứng và cập nhật DOM hiệu quả, các thư viện này còn cung cấp các cách để xây dựng các thành phần có thể tái sử dụng. Ví dụ: ví dụ React sau sử dụng thành phần
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
0const App = [] => {
const [pos, setPos] = React.useState[50];
return [
setPos[ev.target.value] }
>
];
};
const SlidingText = [{ pos }] => [
drag the slider to move me
];
const root = ReactDOM.createRoot[document.getElementById["app"]];
root.render[];
[jsfiddle trực tiếp]
Tất nhiên, vanilla JS cũng hỗ trợ các Thành phần Web, nhưng việc xác định chúng tốn nhiều công sức hơn một chút so với một chức năng đơn giản
Cập nhật DOM với dữ liệu mới
Bạn đề cập đến các yêu cầu Ajax để tải nội dung mới vào trang hiện tại, nhưng trừ khi bạn tải trực tiếp HTML và sử dụng phương pháp
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
2, bạn sẽ phải thao tác DOM bằng cách nào đó. Ví dụ: giả sử chương trình phụ trợ của chúng tôi cung cấp cho chúng tôi danh sách các chuỗi const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
2Với vanilla JavaScript, chúng tôi phải dùng đến một số biến dạng nghiêm trọng như
const list = document.getElementById["data"];
const renderData = [data] => {
list.innerHTML = ''; // delete old contents
for [const item of data] {
const li = document.createElement["li"];
li.innerText = item;
list.appendChild[li];
}
};
Nhưng với React, chúng ta có thể khai báo ánh xạ dữ liệu tới một DOM mong muốn
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
0Và nếu chúng ta cung cấp cho mỗi mục danh sách một
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
3 duy nhất, thì thuật toán hợp nhất/đối chiếu của React có thể xử lý các cập nhật tiếp theo của danh sách đầu vào hiệu quả hơn mà không cần phải viết lại toàn bộ DOM của danh sách khi các phần tử được chèn/xóaPhần kết luận
Tất cả những nỗ lực thêm này có đáng không? . Nhưng việc quản lý và kết xuất trạng thái kiểu React trở nên khá hấp dẫn đối với các ứng dụng một trang, giao diện người dùng động cao hoặc khi bạn muốn nhiều phiên bản của cùng một thành phần tương tác
Tất nhiên, không phải website nào cũng có tính tương tác cao. Trong nhiều trường hợp, các mẫu kết xuất trên phần phụ trợ là hoàn toàn ổn. Thay thế một phần nội dung bằng
const slider = document.getElementById["slider"];
const text = document.getElementById["text"];
slider.addEventListener['input', ev => text.style.left = `${ev.target.value}vw`];
2 là hoàn toàn ổn đối với nhiều trường hợp sử dụng. Ví dụ, tải động các đoạn HTML khá phổ biến và thành công trong cộng đồng Rails với các framework như Turbolinks/Turbo/Hotwire. Ví dụ: giao diện web GitHub sử dụng phương pháp này cho điều hướng chính của nó¹ mặc dù đôi khi React được sử dụng để hiển thị phía máy chủ, một trường hợp sử dụng cạnh tranh với các công cụ mẫu truyền thống