Xây dựng giải pháp quản lý trạng thái cho Creative Tools' Editors

Nov 28 2022
Giới thiệu Trong bài viết này, chúng tôi sẽ chia sẻ một số hiểu biết (hơi cố ý) của chúng tôi về việc thiết kế và xây dựng các giải pháp quản lý trạng thái có thể mở rộng trong bối cảnh các trình chỉnh sửa công cụ sáng tạo với React, Immer và Recoil làm nền tảng cho phương pháp tiếp cận của chúng tôi. Để minh họa rõ hơn cách tiếp cận của chúng tôi, chúng tôi sẽ bao gồm một số ví dụ về mã và một nguyên mẫu nhỏ.

giới thiệu

Trong bài viết này, chúng tôi sẽ chia sẻ một số hiểu biết (hơi cố ý) của chúng tôi về thiết kế và xây dựng các giải pháp quản lý trạng thái có thể mở rộng trong bối cảnh các trình chỉnh sửa công cụ sáng tạo với React, Immer và Recoil làm nền tảng cho phương pháp tiếp cận của chúng tôi.

Để minh họa rõ hơn cách tiếp cận của chúng tôi, chúng tôi sẽ bao gồm một số ví dụ về mã và một nguyên mẫu nhỏ.

Chúng tôi đã sử dụng kiến ​​thức này trong một vài dự án khác nhau, cho phép chúng tôi dễ dàng thoát khỏi một số cạm bẫy phổ biến nhất.

Trạng thái ứng dụng so với trạng thái thiết kế

Một trong những điểm khác biệt chính mà chúng ta có thể tạo ra trong các loại ứng dụng này là trạng thái Ứng dụng so với trạng thái Thiết kế.

trạng thái thiết kế

Mô tả nội dung do người dùng tạo, ví dụ: văn bản (phông chữ, kích thước, màu sắc, nội dung), hình ảnh, các phần tử được nhóm, các phần tử được kết nối, v.v.

Trạng thái thiết kế thay đổi mỗi khi thiết kế thay đổi về mặt khái niệm, nhưng không thay đổi khi người dùng thực hiện các hành động không ảnh hưởng đến thiết kế.

Một số ví dụ về các hành động tác động đến trạng thái thiết kế:

  • Di chuyển một phần tử
  • Thay đổi thuộc tính của văn bản (màu sắc, kích thước, phông chữ)
  • các phần tử nhóm

Xác định trạng thái ứng dụng hiện tại, không bao gồm thiết kế. Trạng thái ứng dụng thay đổi khi người dùng tương tác với ứng dụng và menu của họ.

Vài ví dụ:

  • Chọn một phần tử
  • Mở hộp thoại để chỉnh sửa thuộc tính của phần tử
  • Hiển thị menu chuột phải
  • Xác nhận một hành động

Mỗi loại trạng thái có những đặc điểm riêng, cái này không áp dụng cho loại kia và sẽ khiến việc triển khai của chúng ta phức tạp hơn nếu được giữ cùng nhau.

Ví dụ:

  • Khi lưu một thiết kế, chỉ phần trạng thái này được lưu.
  • Hoàn tác/làm lại chỉ áp dụng cho trạng thái thiết kế. Ứng dụng phải có khả năng hoạt động trong điều kiện có sự không nhất quán nhỏ giữa thiết kế và trạng thái ứng dụng, chẳng hạn như khi phần tử được chọn không còn trong thiết kế do hoàn tác.
  • Khi tải một thiết kế, trạng thái thiết kế được đặt đơn giản với thiết kế, trong khi trạng thái ứng dụng chủ yếu được khởi tạo với giá trị mặc định.

trạng thái ứng dụng

Bất cứ khi nào có thể, chúng ta phải ưu tiên trạng thái cục bộ hơn trạng thái toàn cầu, trạng thái ứng dụng cũng không ngoại lệ.

Việc phân tích mã và luồng của nó trở nên dễ dàng hơn khi chúng ta sử dụng trạng thái cục bộ, các thành phần phải truyền dữ liệu giữa nhau một cách rõ ràng và các tương tác của chúng phải rõ ràng, không có hiệu ứng sử dụng “ẩn xa” mà chúng ta phải tìm kiếm thủ công.

trạng thái thiết kế

Khi xác định trạng thái thiết kế, chúng ta phải có những cân nhắc sau:

  • Có thể lấy và thiết lập toàn bộ trạng thái để chúng ta có thể dễ dàng thực hiện:
    – Tải và lưu thiết kế
    – Hoàn tác/làm lại
  • Tránh hiển thị tất cả các phần tử khi chỉ một số trong số chúng thay đổi

Một trong những cách dễ nhất để triển khai hoàn tác/làm lại trong ứng dụng React là sử dụng I mmer để tạo các bản vá sửa đổi.

Immer là một thư viện JS cho phép chúng ta viết các sửa đổi dữ liệu trong ngữ cảnh không thay đổi (ví dụ: trạng thái React) theo “cách có thể thay đổi”.

Một tính năng khác của Immer là tạo các bản vá thực hiện và hoàn tác của một sửa đổi, điều này cho phép chúng tôi lưu cách thực hiện lại thay đổi mà chúng tôi đã thực hiện và cách quay lại trạng thái xem trước.

Sau mỗi lần thay đổi trạng thái, chúng ta nên lưu các bản vá thực hiện và hoàn tác, đồng thời sử dụng chúng khi người dùng kích hoạt hoàn tác/làm lại.

Tại sao chúng ta cần lấy và đặt toàn bộ trạng thái cùng một lúc?

Giải pháp thay thế là không có nó cùng nhau, đây dường như không phải là vấn đề lớn đối với việc tải và lưu, chúng ta chỉ cần lấy/đặt tất cả các phần trạng thái khác nhau.

Nhưng nó trở thành một vấn đề khi chúng ta phải thực hiện hoàn tác/làm lại. Đối với mỗi phần trạng thái, chúng tôi phải lưu các bản vá đã tạo, với siêu dữ liệu cho biết phần trạng thái đó dành cho phần nào và đọc nó khi thao tác hoàn tác được kích hoạt để chúng tôi có thể sửa đổi phần trạng thái chính xác.

Ngoài ra, vì một hành động của người dùng có thể sửa đổi nhiều phần trạng thái như một thao tác, nên chúng tôi phải theo dõi các bản vá nào thuộc cùng một thao tác để chúng tôi có thể hoàn tác và làm lại chúng cùng một lúc.

Sử dụng một trạng thái duy nhất sẽ giải quyết tất cả những điều này

  • Không có hành động sửa đổi nhiều trạng thái
  • Tất cả các bản vá áp dụng cho trạng thái, không áp dụng cho nhiều trạng thái phân tán.

Cách dễ dàng hơn để thỏa mãn lựa chọn thiết kế này là lưu toàn bộ trạng thái thiết kế vào cùng một chỗ. Điều đó sẽ khiến chúng tôi nghĩ rằng useState<DesignState>(defaultState), như bạn có thể đoán, điều này khiến chúng tôi thất bại trong việc cân nhắc “hiển thị hầu hết ứng dụng”:

Không hiển thị hầu hết ứng dụng khi thiết kế thay đổi

Để giải quyết vấn đề này, chúng tôi thường sử dụng Recoil, một thư viện quản lý trạng thái cho React.

Recoil có hai khái niệm chính : nguyên tử và bộ chọn.

Nguyên tử : đơn vị trạng thái, có thể được sử dụng theo cách tương tự như useState, nhưng trên toàn cầu, chẳng hạn

Khi useStatetriển khai, trong đoạn mã trên, tất cả DesignElements sẽ hiển thị bất cứ khi nào bất kỳ phần tử nào (hoặc bất kỳ phần nào của trạng thái) thay đổi. Để giải quyết vấn đề này, chúng ta có thể sử dụng bộ chọn.

Bộ chọn : các hàm tạo phép chiếu từ một nguyên tử hoặc bộ chọn khác. Khi một thành phần React sử dụng bộ chọn, nó sẽ chỉ hiển thị lại (với một số lưu ý) khi kết quả của bộ chọn thay đổi.

Recoil cũng cho phép chúng ta nhận các đối số trong hàm xác định bộ chọn, các loại bộ chọn đó được gọi là selectorFamily. Chúng ta có thể sử dụng điều này để tạo một selectorFamily nhận một phần tửId và cung cấp cho chúng ta phần tử đó.

Khi một phần tử được sửa đổi, đoạn mã trên chỉ kích hoạt một bản cập nhật cho DesignElement phù hợp và không hiển thị tất cả các phần tử hoặc thành phần Thiết kế.

Một người quan sát cẩn thận có thể thấy rằng thành phần Thiết kế sẽ hiển thị bất cứ khi nào một thành phần được thêm hoặc xóa, kích hoạt kết xuất lại tất cả các Thành phần thiết kế. Nếu điều này gây ra các vấn đề về hiệu suất cho một trường hợp sử dụng cụ thể, chúng tôi có thể bọc thành phần DesignElement của mình trong tệp React.memo.

Đặt trạng thái

Bởi vì chúng tôi muốn các bộ của mình được áp dụng cho DesignState cấp cao nhất (để đơn giản hóa việc hoàn tác/làm lại), chúng tôi có thể tạo các lệnh gọi lại độ giật để đóng gói logic sửa đổi của chúng tôi và tạo các bản vá hoàn tác/làm lại.

Một ví dụ tối thiểu có thể được tìm thấy trong Codesanbox này.

Đóng cửa

Trong bài đăng trên blog này, chúng tôi đã chia sẻ đâu là động lực chính khi thiết kế quản lý trạng thái trong bối cảnh trình chỉnh sửa của công cụ sáng tạo và cách triển khai của chúng tôi đáp ứng yêu cầu đó.

Nếu bạn đọc hết đến đây, tôi rất muốn biết ý kiến ​​​​của bạn. Bạn có thể liên hệ với tôi ở đây .

Tại Zeppelin Labs, chúng tôi giúp những người sáng lập và các công ty đang phát triển thử nghiệm và xây dựng các sản phẩm kỹ thuật số khác biệt nhằm thúc đẩy tăng trưởng. Bạn có thể tìm thấy chúng tôi ở đây . Hoặc ở đây . Hoặc ở đây .

Nếu bạn muốn tham gia nhóm của chúng tôi, hãy gửi email cho chúng tôi tại [email protected]

Muốn hợp tác? gửi email cho chúng tôi tại quan hệ đối tá[email protected]

Theo dõi Bản tin của chúng tôi tại đây .