Helpex - Trao đổi & giúp đỡ Đăng nhập

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Trong bài viết này, tôi sẽ giải thích cách Redux Toolkit đơn giản hóa việc xây dựng các ứng dụng dựa trên Redux và kết hợp tuyệt vời với React và TypeScript để tạo ra một ngăn xếp tuyệt vời toàn diện.

Tại sao tôi lại nói về điều này?

Tôi muốn truyền bá một ngăn xếp mà chúng tôi rất thích và đã thành công ở đây tại Instil - React + TypeScript + Redux Toolkit. Nhưng tôi không chắc sẽ nói về khía cạnh nào hoặc giới thiệu nó với ai. Nhìn vào Trạng thái của JavaScript 2019 , tôi biết rất nhiều bạn đang xây dựng ứng dụng với React.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Khung giao diện người dùng

Tôi cũng biết rằng về mặt ngôn ngữ, TypeScript rất phổ biến (mặc dù không nhất thiết phải bằng React) ,.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Hương vị JavaScript

Nhìn vào việc quản lý dữ liệu, Redux cũng phổ biến nhưng một con số thú vị dưới đây là 19,8% người đã sử dụng Redux trước đây nhưng sẽ không sử dụng lại.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Lớp dữ liệu

Ngoài ra, nhìn vào Google Xu hướng, số lượng tìm kiếm cho Redux thấp hơn so với Redux Toolkit.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Vì vậy, trong bài viết này, tôi tập trung vào,

  • Các lợi ích của việc tách trạng thái khỏi chế độ xem nói chung

  • Đánh giá nhanh về cách Redux thực hiện điều này

  • Sử dụng Bộ công cụ Redux để đơn giản hóa Redux

    • Đặc biệt quan trọng nếu bạn đã dùng thử Redux đơn giản và cảm thấy khó khăn

  • Tất cả được trình bày trong ngữ cảnh của React và TypeScript

Tôi hy vọng rằng vào cuối bài viết này, bạn sẽ thấy Redux ít đáng sợ hơn và bạn sẽ được khuyến khích dùng thử nó cùng với TypeScript cho một dự án React. Ứng dụng mẫu mà tôi đã tạo cho bài viết này là một máy tính dựa trên web cơ bản,

Tôi giả sử rằng bạn có kiến ​​thức làm việc cơ bản về React và TypeScript (mặc dù có lẽ không cùng nhau hoặc không giận dữ). Nếu bạn muốn tìm hiểu sâu hơn về bất cứ điều gì tôi đề cập, vui lòng Thích và để lại bình luận bên dưới.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Trạng thái tách và giao diện người dùng

React là một khung công tác hoàn toàn tập trung vào việc xây dựng các khung nhìn và nó làm rất tốt điều đó. Cú pháp ngắn gọn và sự đan xen của bộ mô tả chế độ xem JSX với các phần tử lập trình tiêu chuẩn tạo điều kiện dễ dàng xây dựng giao diện người dùng dựa trên thành phần.

export const Buttons = () =>
  <div>
    {buttons.map((row, rowIndex) => (
       <div key="{rowIndex}" classname='row no-gutters'>
         {row.map((button, colIndex) => <button key="{colIndex}" value="{button}"></button>)}
       </div>
     ))}
  </div>


Những gì nó không làm rất tốt là trạng thái xử lý. Việc ghép nối trạng thái với các khung nhìn của chúng ta và trạng thái đi qua các cây lớn của các thành phần là mong manh và vụng về. Bất cứ khi nào trạng thái được sở hữu bởi các thành phần, sẽ có nhiều logic nghiệp vụ hơn nằm trong chúng, điều này tạo nên vấn đề.

Một giải pháp thanh lịch hơn nhiều để tách logic miền và trạng thái của chúng tôi khỏi chế độ xem của chúng tôi. Sau đó, chúng tôi có thể tùy ý chọn các thành phần để liên kết - chúng tôi chỉ ràng buộc những gì cần thiết, nơi cần thiết.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Được tách rời, logic trạng thái và miền dễ phát triển hơn. Việc loại bỏ các mối quan tâm về chế độ xem giúp việc gỡ lỗi và kiểm tra dễ dàng hơn nhiều và cho phép chúng tôi tập trung vào các phép biến đổi dữ liệu đơn giản. Chúng tôi có thể lập mô hình hệ thống của mình dưới dạng dữ liệu và mô tả về cách dữ liệu của chúng tôi thay đổi dựa trên các sự kiện xâm nhập vào hệ thống. Điều này cho phép chúng tôi giảm đáng kể tải nhận thức khi chúng tôi xây dựng các ứng dụng phức tạp hơn.

Chế độ xem cũng dễ làm việc hơn vì các thành phần nhỏ hơn và chỉ tập trung vào việc hiển thị mẫu dựa trên một số trạng thái. Việc cấu trúc lại giao diện người dùng, chia tách hoặc kết hợp các thành phần trở nên dễ dàng. Chúng ta có thể di chuyển và chia sẻ nơi trạng thái được sử dụng trong cây một cách dễ dàng vì chúng ta có thể tùy ý ràng buộc bất kỳ trạng thái nào với bất kỳ phần nào của khung nhìn. Ví dụ: sao chép tổng giỏ hàng từ một thành phần ở cuối màn hình lên thanh công cụ ở trên cùng hoặc sử dụng trạng thái bận trên một số thành phần.

Redux Refresher

Redux là một khung quản lý trạng thái phổ biến và thường được kết hợp với React (cũng thúc đẩy tư duy chức năng và bất biến mà Redux ủng hộ).

Trong mô hình Redux chúng ta có,

  • Lưu trữ - điều này chứa và quản lý trạng thái của chúng tôi

  • Hành động - mô tả một sự thay đổi trạng thái (bạn có thể coi đây là một sự kiện)

    • Một đối tượng đơn giản mô tả sự thay đổi

    • Các chức năng của Action Creator giúp việc tạo chúng trở nên đơn giản hơn

  • Giảm tốc - một chức năng thuần túy có trạng thái hiện tại, một hành động và sẽ tính toán trạng thái tiếp theo

Vì vậy, quy trình chung là chúng ta bắt đầu với một số trạng thái ban đầu và sau đó chúng ta có thể gửi các hành động đến store sẽ sử dụng bộ giảm tốc để tính toán trạng thái mới. Chế độ xem lắng nghe cửa hàng và được thông báo khi có điều gì đó thay đổi.

Bộ công cụ React + TypeScript + Redux - An toàn và Đơn giản

Không đi vào quá nhiều chi tiết, hệ thống dựa vào tính bất biến của cấu trúc dữ liệu trạng thái, đó là lý do tại sao bộ giảm là một hàm thuần túy (không có tác dụng phụ). Khi chúng ta có cấu trúc dữ liệu bất biến, việc kiểm tra xem có gì đó đã thay đổi hay không (và do đó biết được liệu giao diện người dùng có phải kết xuất hay không) là điều không cần thiết vì nó chỉ đơn giản là một so sánh tham chiếu - để khác đi, nó phải là một đối tượng khác.

Xem xét ứng dụng Máy tính của chúng tôi, chúng tôi sẽ trình bày điều này như thế nào trong Redux?

  • Trạng thái - Hệ thống sẽ cần đại diện cho điều gì?

    • Số hiện tại đang được nhập

    • Kết quả trước đó

    • Hoạt động hiện tại

  • Hành động - Những sự kiện nào có thể xảy ra với ứng dụng của chúng tôi?

    • Nút được nhấn - chúng có thể được phân rã thêm, ví dụ như số, hoạt động, bằng, v.v.

  • Bộ giảm tốc - Hành động của quy trình + trạng thái để tạo ra trạng thái tiếp theo

    • Xử lý một lần nhấn nút

Bộ công cụ Redux

Việc triển khai các hành động, bộ giảm thiểu và trạng thái trong Redux thông thường yêu cầu viết rất nhiều mã soạn sẵn. Chức năng thuần túy và ràng buộc bất biến trên bộ giảm thiểu cũng làm phức tạp thêm mọi thứ.

Trước đây, tôi đã viết các trình trợ giúp của riêng mình để giảm bớt một số vấn đề này, nhưng Bộ công cụ Redux hiện ở đây để loại bỏ nhu cầu tự làm việc này. Nó dễ dàng được thêm vào một dự án,

npm install –save @reduxjs/toolkit

Điều tuyệt vời là nó đi kèm với các ràng buộc TypeScript.

Actions, Reducers và Slices

Bộ công cụ cung cấp các trình trợ giúp để tạo các phần tử tiêu chuẩn - lưu trữ, giảm thiểu, hành động, hành động không đồng bộ, v.v. Mặc dù vậy, hữu ích hơn nữa là khái niệm về một Slice, cho phép chúng ta thiết lập trạng thái, trình giảm và hành động của mình trong một vùng chứa.

const slice = createSlice({
  name: 'some-name',
  initialState: {
    // ...
  },
  reducers: {
    // ...
  }
});


Đối tượng 'Reducers' xác định các hàm vừa xác định một hành động vừa xác định logic rút gọn cho hành động cụ thể đó. Hơn nữa, hàm giảm thiểu có thể được viết theo kiểu bất biến, trả về trạng thái mới hoặc có thể được viết theo kiểu có thể thay đổi.

Bộ công cụ sử dụng một thư viện khác, Immer , để hàm có thể được viết bằng cách sử dụng đột biến đơn giản. Phía sau hậu trường, Immer, sẽ chuyển một đối tượng trạng thái proxy, theo dõi các thay đổi và sau đó thực hiện các phép biến đổi bất biến cần thiết. Điều này có thể đơn giản hóa một số thao tác như thực hiện các thay đổi trong các cấu trúc hoặc mảng đối tượng được lồng sâu và các cấu trúc dữ liệu khác.

Slice tạo ra các chức năng giảm thiểu thuần túy và một tập hợp các chức năng tạo hành động có thể được xuất. Ví dụ: với máy tính của chúng tôi, chúng tôi kết thúc với,

export interface State {
  value: string;
  operation?: Operation;
  previousValue?: string;
}

const slice = createSlice({
  name: 'calculator',
  initialState: {
    value: '0',
    previousValue: undefined,
    operation: undefined
  } as State,

  reducers: {
    keyPressed(state: State, {payload: key}: PayloadAction<string>) {
      // ...
    }
  }
});


export const reducer = slice.reducer;
export const {keyPressed} = slice.actions;</string>

Điều tuyệt vời về tất cả những điều này là nó thuộc loại an toàn (và không có nhiều chú thích bổ sung). Các trình tạo hành động được tạo, chẳng hạn như keyPressed, sẽ lấy các loại tham số chính xác dựa trên định nghĩa hàm trong phần bộ giảm.

keyPressed(state: State, {payload: key}: PayloadAction<string>) {
  // ...
}
...

keyPressed('3'); // Valid
keyPressed(3);   // Invalid</string>


Chúng tôi cũng có thể bao gồm các hành động được tạo bên ngoài (trong một phần khác hoặc sử dụng trình trợ giúp hành động tạo) trong phần 'extraReducers' của tham số 'createSlice' của chúng tôi ..

Cửa hàng

Tạo cửa hàng cũng dễ dàng hơn với bộ công cụ. Chức năng 'configStore' tạo một cửa hàng bằng cách sử dụng một trình giảm bớt giống như chức năng 'createStore' cũ nhưng nó nằm trong phần mềm trung gian hữu ích theo mặc định. Phần mềm trung gian là cách các cửa hàng Redux có thể được mở rộng để xử lý các hành động một cách tập trung. Theo mặc định, bạn không có nhưng với bộ công cụ, nó có:

  • Redux Thunk - cho phép chúng tôi gửi các hàm dưới dạng hành động cho các hành động không đồng bộ

  • Redux Dev Tools - bật tiện ích mở rộng trình duyệt Redux Dev Tools

  • Bất biến Bất biến - đảm bảo rằng các chuyển đổi trạng thái luôn bất biến

  • Serializability Invariant - đảm bảo hành động và trạng thái luôn có thể tuần tự hóa.

3 dưới cùng chỉ tự động được bật trong chế độ gỡ lỗi.

const store = configureStore({
    reducer
});

Khả năng kiểm tra

Cho đến nay, tôi đã có thể phát triển logic cốt lõi của ứng dụng mà không cần tập trung nhiều vào chế độ xem. Sự tách biệt các mối quan tâm này rất mạnh mẽ. Nó cũng tạo điều kiện cho việc kiểm tra dễ dàng vì chức năng giảm tốc là thuần túy và chúng ta chỉ cần xác định đầu vào và đầu ra.

it(`should handle previous operation when new operation pressed`, () => {
  const result = target({
    value: '10',
    previousValue: "12",
    operation: '-'
  }, keyPressed('+'));

  expect(result.previousValue).toEqual(undefined);
  expect(result.value).toEqual('2');
  expect(result.operation).toEqual('+');
})

it(`should replace op when op present but no previous value`, () => {
  const result = target({
    value: '10',
    previousValue: undefined,
    operation: '-'
  }, keyPressed('+'));

  expect(result.previousValue).toEqual(undefined);
  expect(result.value).toEqual('10');
  expect(result.operation).toEqual('+');
});


Tận dụng thực tế là chúng tôi xác định các thử nghiệm bằng cách gọi hàm 'it' (hoặc 'thử nghiệm'), chúng tôi có thể viết các thử nghiệm tham số hóa một cách dễ dàng bằng cách sử dụng lệnh gọi forEach,

[

  {value: '0', key: '0', expected: '0', name: 'Enter 0 with zero already present'},
  {value: '0', key: '4', expected: '4', name: 'Enter 4 with zero already present'},
  {value: '',  key: '1', expected: '1', name: 'Enter 1'},
  {value: '1', key: '2', expected: '12', name: 'Second digit'},
  {value: '0', key: '.', expected: '0.', name: 'Entering . on zero'},
  // ...
].forEach(({value, key, expected, name}) =>
  it(`should handle key presses correctly - ${name}`, () => {
    // ...
  })
);


Một lần nữa, tất cả những điều này đều đẹp hơn trong TypeScript vì đối tượng dữ liệu thử nghiệm có thể là bất kỳ hình dạng nào nhưng trình biên dịch vẫn biết loại và sẽ cung cấp cho chúng tôi tính năng kiểm tra lỗi, tự động hoàn thành, kiểm tra kiểu, đổi tên tái cấu trúc, v.v.

Lưu ý, trong Jest, nó và thử nghiệm có các dạng tham số được tích hợp sẵn, nhưng chúng không phù hợp với dữ liệu thử nghiệm phức tạp như sử dụng forEach.

Kết nối với React

Bây giờ chúng ta đã đề cập đến việc xây dựng logic miền và trạng thái của chúng ta, hãy đi sâu vào chế độ xem. Bộ công cụ không giúp kết nối trạng thái với các khung nhìn phản ứng, nhưng thư viện react-redux cốt lõi đã tự phát triển để hỗ trợ Redux Hooks. Điều này giúp dễ dàng kết nối bất kỳ phần nào trong trạng thái của chúng ta với các thành phần bằng chức năng hook useSelector.

export const Display = () => {
  const value = useSelector((state: State) => state.value);
  const operator = useSelector((state: State) => state.operation);

  return (
    <div classname='row'>
      <div classname='col-1'>{operator}</div>
      <div classname="{`col-5" border="" text-right="" ${styles.display}`}="">
        {value}
      </div>
    </div>
  );
}


Với useSelectorhook, chúng tôi không chỉ sử dụng trạng thái này khi kết xuất, chúng tôi đang thiết lập thành phần này để nó sẽ tự động kết xuất lại nếu trạng thái này thay đổi. Lưu ý, nó không phải là nếu bất kỳ trạng thái nào thay đổi, chỉ là trạng thái được giải nén.

Tương tự như vậy, thật dễ dàng để thực hiện bất kỳ hành động nào bằng hook useDispatch

const Button: FC<buttonprops> = ({value}) => {
  const dispatch = useDispatch();
  
  return <button onclick="{()" ==""> dispatch(keyPressed(value.content))}>
           {value.content}
         </button>;
}</buttonprops>


Cũng lưu ý rằng thành phần này được gõ mạnh. React cũng hỗ trợ TypeScript tuyệt vời và chúng ta có thể nhập các thành phần chức năng của mình bằng 'FC' và thêm một loại đạo cụ tùy chọn, trong trường hợp này là ButtonProps,

interface ButtonProps {
  value: ButtonDescriptor;
}


TypeScript sẽ đảm bảo các đạo cụ được nhập chính xác, dễ dàng bị hủy và các thành phần của chúng tôi được sử dụng đúng cách trong JSX.

Phần kết luận

Tôi hy vọng rằng bài viết này cung cấp cho bạn một số thông tin chi tiết về cách sử dụng React và Redux cùng nhau trong một thiết lập hiện đại, sử dụng TypeScript và Redux Toolkit để tăng độ an toàn và giảm bớt các bản viết sẵn. Còn rất nhiều chi tiết mà tôi có thể đi sâu vào, vì vậy vui lòng Thích bài viết và để lại bình luận bên dưới cho các chủ đề khác cho các bài viết trong tương lai.


Nếu bạn đang tìm kiếm các khóa học chuyên sâu về TypeScriptReact, hãy xem các liên kết trước đó. eam

21 hữu ích 0 bình luận 10k xem chia sẻ

Có thể bạn quan tâm

loading