Sử dụng Redux store như 1 database
redux
14
Javascript
297
White

Huy Quang viết ngày 25/03/2019

Chúng ta nên cấu trúc data trong redux như thế nào?

Đây là một câu hỏi thường gặp khi sử dụng redux, chắc chắn tôi đã tự hỏi mình nhiều lần. Tôi đã tìm được câu trả lời, nó phụ thuộc vào dự định tôi tương tác với dữ liệu của mình.
Có một số thứ cần tính tới: format dữ liệu có được lặp lại giống như rows trong list không? Có cần nhanh (độ phức tạp tới O(1)) khi truy cập vào dữ liệu đơn lẻ hay không?
Tôi đã nhìn thấy một loạt cách tiếp cận trong thực tế, thường thì một số cân bằng giữa thời gian truy cập và dễ dàng lặp lại.

Cách tiếp cận thông thường

Nếu bạn đang tổ chức dữ liệu dưới dạng các mục(mỗi mục đều có khoá id), bạn có thể giữ chúng trong một Object hoặc 1 mảng các Object.

Mảng các flat objects [{values}]

Đây là cách thông thường nhất tôi thấy. Nó sử dụng vòng lặp dễ dàng và bạn có thể lưu trữ liệu của mình theo một thứ tự cụ thể, nhưng bạn không thể truy cập theo id hoặc tên mà không cần lặp lại và lọc.

categories: [
  {name: 'abs',  id: '32o8wafe', exercises: ['crunches', 'plank']},
  {name: 'arms', id: 'oaiwefjo', exercises: [...]},
  {name: 'legs', id: 'aoijwfeo', exercises: [...]},
]

Mảng theo kiểu key, value {id: {values}}

Điều này cho phép chúng ta truy cập nhanh với độ phức tạo O(1) vào từng mục, nhưng bạn không thể dễ dàng truy cập id của một mục nhất định.

categories: {
  '32o8wafe': {name: 'abs',  exercises: ['crunches', 'plank']},
  'oaiwefjo': {name: 'arms', exercises: [...]},
  '3oij2e3c': {name: 'legs', exercises: [...]},
}
Object.values(categories).map(row => // Không thể tìm được id ở đây)
//Điều đó là tương tự với Object.entries, nhưng bạn vẫn không thể lấy row.id

Cấu trúc nó giống như một database nhiều row và được đánh index bằng ID (Same Dynamodb )

Chúng tôi tiến hành một thử nghiệm trên một ứng dụng redux lớn, chúng tôi tình cờ tìm thấy một cách tiếp cận khác mang lại cho chúng ta lợi ích, cả việc lặp với Object.values và truy cập nhanh từng mục riêng lẻ với độ phức tạp O(1)

categories: {
  '32o8wafe': {id: '32o8wafe', name: 'abs',  exercises: [...]},
  'oaiwefjo': {id: 'oaiwefjo', name: 'arms', exercises: [...]},
  '3oij2e3c': {id: '3oij2e3c', name: 'legs', exercises: [...]},
}

Lưu ý, id được sử dụng vừa là khoá của hàng và vừa là thuộc tính của hàng. Nó giúp việc truy cập linh hoạt hơn. Nó cũng tương thích với các hình dạng bình thường mà document của Redux giới thiệu.

Bây giờ bạn có thể lặp qua dữ liệu và truy cập vào id trong vòng lặp.

Object.values(categories).map(cat => ({id: cat.id, name: cat.name}))

Hoặc truy cập vào dữ liệu đơn lẻ từng Id

categories[‘32o8wafe’].name // 'abs'

Sức mạnh của Indexes

Cấu trúc mới chúng tôi giới thiệu trên chỉ là một thay đổi nhỏ, và không giống như một team dành nhiều thời gian để thiết kế Redux store. Điều khác biệt chỉ có thể nhận ra khi chúng ta truy cập dữ liệu lưu trữ bằng cách sử dụng các khoá ngoài khác nhau của ID
Lưu ý: Cấu trúc chúng tôi giới thiệu trên chỉ là một dạng danh sách các hàng, với một khoá được sử dụng để xác định duy nhất mỗi hàng. Với redux store được tổ chức như thế này, bạn có thể tạo ra chỉ mục sau đó truy cập nhanh từng khoá với độ phức tạp chỉ O(1)

Đánh index categories theo name:

Để đánh index, chúng ta viết một function lấy dữ liệu store và trả về một mapping name -> id

const index_by_name = (categories) =>
    Object.values(categories)
          .reduce((obj, row) => (obj[row.name] = row.id, obj), {})
// {abs: '32o8wafe', arms: 'oaiwefjo', legs: '3oij2e3c'}

alt text

const ids_by_name = index_by_name(categories)
categories[ids_by_name['abs']] // {id: '32o8wafe', name: 'abs', ...}

Bạn có thể build nhiều Indexes như bạn muốn với dữ liệu tương tự, giúp bạn truy cập từng cột với độ phức tạp chỉ O(1), giống như bạn có một database.

Nếu dữ liệu của bạn không thay đổi, indexes của bạn chỉ cần tính toán một lần, hoặc không chúng nên được tính toán lại bằng "Memorized" function.

Sắp xếp dữ liệu

Điều gì sẽ xảy ra nếu danh mục của bạn có thứ tự vốn có (như trong một mảng), và bạn cần lấy chúng theo thứ tự?
Bạn có thể nghĩ làm cái gì đó như:

const category_order = ['32o8wafe', 'oaiwefjo', '3oij2e3c']
category_order.map(id => categories[id])

Đây là một cách tiếp cận tốt, tuy nhiên, nó yêu cầu giữ một mảng riêng biệt, tối ưu từ data của chúng ta để lưu sự sắp xếp. Hãy làm điều đó với indexes.

Chúng tôi gửi dữ liệu đến backend với một dãy order (hoặc idx) key chỉ định vị trí mỗi hàng, sau đó làm một khoá cho order giống như chúng ta làm với bất kỳ khoá nào:

const ids_by_order =
      Object.values(categories)
            .reduce((ordered_ids, category) => {
                        ordered_ids[category.order] = category.id
                        return ordered_ids
                    }, [])
// ['32o8wafe', 'oaiwefjo', '3oij2e3c']

Lưu ý: Cách này có thể làm giảm số lượng phần tử trong mảng (Xảy ra khi các ptu vị trí). Trong JS, một mảng là thực ra chỉ là một object với keys 0,1,2..., vì vậy chúng ta có độ phức tạp bằng O(1) với một ID đặc biệt hay thứ tự, và chúng ta có thể dùng vòng lặp với map, filter và reduce trên danh sách đã sắp xếp

const second_category = categories[ids_by_order[1]]
// {id: 'oaiwefjo', name: 'arms', order: '1'}
const ordered_names = ids_by_order.map(id => categories[id].name)
// ['abs', 'arms', 'legs']

Memoization

Nếu dữ liệu của bạn không thay đổi, bạn có thể gọi ids_by_key một lần khi startup và sử dụng để tạo index như một đối tượng tĩnh mọi lúc sau đó. Tuy nhiên, nếu bạn đang làm việc với dữ liệu thay đổi sẽ được truy cập thường xuyên, kĩ thuật ghi nhớ (memoization) là cần thiết để tránh tính toán lại chỉ mục trên mọi truy cập.

Bộ chọn Memoized-index có thể được làm với reselect hoặc viết bởi một custom memoizer function (Nó không quá khó, phụ thuộc vào dữ liệu của bạn).

Memoized indexes nghĩa bạn có thể gọi function lấy index mọi lúc, thay vì phải lưu chỉ mục trong Redux.

Mô hình dữ liệu phẳng với indexes mà tôi mô tả trên cũng tương đương đồng với mô hình sử dụng bởi thư viện Normalizr. Nếu bạn lưu trữ dữ liệu của mình phẳng(được phân tách theo type), và thích khái niệm concept giới thiệu trong bài viết, thì nên đọc bài viết Redux Without Profanity docs trên Normalizr.

Để update cho memoization, bạn có thể thay đổi bất kỳ index nào khi các khoá được thêm vào hay xoá đi. Thiết kế nào bạn sử dụng phụ thuộc vào dạng thức truy cập dữ liệu của bạn.

Hàm sắp xếp index tốt hơn.

Một cách viết hàm sắp xếp khác tốt hơn, khi key được dùng là một tham số đầu vào:

const ids_by_key = (key) => (data) =>  // make index(data) for key
      Object.values(data)
            .reduce((index, row) => {
                        index[row[key]] = row.id
                        return index
                    }, {})
const ids_by_name = ids_by_key('name')  // returns an index function
const abs_id = ids_by_name(categories)['abs']
// '32o8wafe'

Nguồn: Hackernoon

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Huy Quang

3 bài viết.
1 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
5 2
Nguồn: https://codeburst.io/6simplewaystospeedupyourreactnativeappd5b775ab3f16 1. Sử dụng PureComponent hoặc shouldComponentUpdate Khác với Comp...
Huy Quang viết hơn 1 năm trước
5 2
White
2 0
Việc cài cắm server với các bạn dev có kinh nghiệm chắc cũng không quá xa lạ. Document của aws cũng khá rõ ràng, nhưng mình vần muốn dịch lại và ch...
Huy Quang viết hơn 1 năm trước
2 0
Bài viết liên quan
White
4 1
Trải qua 1 thời gian khá dài trải nghiệm Angular, mình thấy RxJS khá hay. Bài này sẽ quay trở lại với bài toán Counter thần kì của React/Redux, như...
cdxf viết 1 năm trước
4 1
White
59 8
Tăng sức mạnh cho javascript với lodash Lần này mình sẽ giới thiệu 1 thư viện javascript vô cùng bá đạo có tên là "lodash]1]", có thể nói nó là LI...
Huy Hoàng Phạm viết gần 4 năm trước
59 8
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
3 bài viết.
1 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!