😇React Context với TypeScript: Phần 3 - Context với các thành phần lớp

https://www.carlrippon.com/react-context-with-typescript-p3/

src\App.tsx

import React,  {Component, createContext, ContextType} from 'react';
// Step 1 Đang cố gắng sử dụng móc ngữ cảnh trong một thành phần lớp
const ThemeContext = createContext<any>(undefined);
// Step 2 
// + Hook chỉ có thể được gọi bên trong các thành phần hàm, do đó, đoạn mã trên sẽ báo lỗi ở dòng sau: const { theme, setTheme } = useTheme()!;
// + Các thành phần lớp React có một thuộc tính context  mà chúng ta có thể sử dụng để sử dụng một ngữ cảnh
// class Header extends Component {
//   static contextType = ThemeContext;
//   context: ContextType<any>;
//   render() {
//     const { theme, setTheme }:any = this.context!;
//     return (
//       <div style={{ backgroundColor: theme }}>
//         <select value={theme} onChange={e => setTheme(e.currentTarget.value)}>
//           <option value="white">White</option>
//           <option value="lightblue">Blue</option>
//           <option value="lightgreen">Green</option>
//         </select>
//         <span>Hello!</span>
//       </div>
//     );
//   }
// }
// Step 3 Lưu ý rằng chúng ta đặt dấu chấm than( !) sau thuộc tính context để báo cho trình biên dịch TypeScript biết rằng đây không phải là undefined
const ThemeProvider: any = ({ children }:any) => {
  const [theme, setTheme] = React.useState("white");
  React.useEffect(() => {
    const currentTheme = "lightblue";
    setTheme(currentTheme);
  }, []);
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
// Step 4 Sử dụng thành phần Consumer
class Header extends Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {value => (
          <div style={{ backgroundColor: value!.theme }}>
            <select
              value={value!.theme}
              onChange={e => value!.setTheme(e.currentTarget.value)}
            >
              <option value="white">White</option>
              <option value="lightblue">Blue</option>
              <option value="lightgreen">Green</option>
            </select>
            <span>Hello!</span>
          </div>
        )}
      </ThemeContext.Consumer>
    );
  }
}
const App:any = () => {
  return (
    <ThemeProvider>
      <Header />
    </ThemeProvider>
  );
}
export default App;

Đây là một bài đăng khác trong loạt bài đăng về React context với TypeScript. Trong bài đăng trước , chúng ta đã tạo một context phức tạp và sử dụng nó trong một thành phần hàm.

Trong bài viết này, chúng ta sẽ tìm hiểu về cách sử dụng React context với các thành phần lớp.

Đang cố gắng sử dụng móc ngữ cảnh trong một thành phần lớp

Chúng ta sẽ tiếp tục sử dụng ngữ cảnh đã tạo ở bài đăng trước cho phép người dùng chia sẻ và thiết lập chủ đề. Hãy cập nhật Headerthành phần thành thành phần lớp:

class Header extends React.Component {
  render() {
    const { theme, setTheme } = useTheme()!;

    return (
      <div style={{ backgroundColor: theme }}>
        <select
          value={theme}
          onChange={e => setTheme(e.currentTarget.value)}
        >
          <option value="white">White</option>
          <option value="lightblue">Blue</option>
          <option value="lightgreen">Green</option>
        </select>
        <span>Hello!</span>
      </div>
    );
  }
}

Tuy nhiên, việc triển khai này có một vấn đề:

Hook chỉ có thể được gọi bên trong các thành phần hàm, do đó, đoạn mã trên sẽ báo lỗi ở dòng sau:

const { theme, setTheme } = useTheme()!;

Sử dụng contexttài sản

Các thành phần lớp React có một contextthuộc tính mà chúng ta có thể sử dụng để sử dụng một ngữ cảnh. Đầu tiên, chúng ta cần cho lớp biết ngữ cảnh nào mà nó nên sử dụng với một static contextTypethuộc tính, sau đó chúng ta có thể truy cập contextthuộc tính đó:

class Header extends React.Component {
  static contextType = ThemeContext;
  render() {
    const { theme, setTheme } = this.context!;
    return (
      ...
    );
  }
}

Lưu ý rằng chúng ta đặt dấu chấm than( !) sau contextthuộc tính để báo cho trình biên dịch TypeScript biết rằng đây không phải là undefined.

Chúng ta hãy xem những loại nào themeđã setThemeđược suy ra như sau:

Cả hai themesetThemeđều được suy ra là có anykiểu.

Thiết lập rõ ràng loại cho contextthuộc tính

Hiện tại, ngữ cảnh được sử dụng không được đánh kiểu mạnh. Chúng ta có thể định nghĩa rõ ràng contextthuộc tính classes bằng chú thích kiểu để làm cho nó được đánh kiểu mạnh:

class Header extends React.Component {
  static contextType = ThemeContext;
  context: React.ContextType<typeof ThemeContext>;
  render() {
    const { theme, setTheme } = this.context!;

    return (
      ...
    );
  }
}

Lưu ý rằng chúng ta không sử dụng React.ContextType<ThemeContextType>chú thích kiểu cho thuộc contexttính vì chúng ta sẽ nhận được lỗi kiểu nếu làm như vậy.

Có thể xem bản triển khai đầy đủ bằng cách nhấp vào liên kết bên dưới. Hãy thử và thay đổi giá trị chủ đề và xem màu nền thay đổi.

Mở triển khai đầy đủ

Sử dụng Consumerthành phần

Có một cách tiếp cận thay thế để sử dụng ngữ cảnh trong thành phần lớp nếu chúng ta chỉ cần truy cập vào nó trong JSX. Phương pháp này là sử dụng Consumerthành phần ngữ cảnh:

class Header extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>        {value => (
          <div style={{ backgroundColor: value!.theme }}>
            <select
              value={value!.theme}
              onChange={e => value!.setTheme(e.currentTarget.value)}
            >
              <option value="white">White</option>
              <option value="lightblue">Blue</option>
              <option value="lightgreen">Green</option>
            </select>
            <span>Hello!</span>
          </div>
        )}
      </ThemeContext.Consumer>    );
  }
}

Thành phần con của Consumerthành phần là một hàm có giá trị của ngữ cảnh được truyền vào và trả về JSX mà chúng ta muốn hiển thị. Lưu ý rằng chúng ta đã đặt dấu chấm than ( !) sau khi tham chiếu valueđể báo cho trình biên dịch TypeScript rằng đây không phải là undefined.

Lợi ích của cách tiếp cận này là thuộc contextTypetính tĩnh không cần phải được triển khai. Chúng ta contextcũng không cần phải khai báo thuộc tính với chú thích kiểu của nó.

Hãy kiểm tra kiểu suy ra của valuetham số trong Consumerhàm con của thành phần:

Kiểu của valuetham số làThemeContextType | undefined

Kết thúc

Chúng ta có thể sử dụng ngữ cảnh Reacts trong các thành phần lớp, nhưng chúng ta không thể sử dụng useContexthook.

Sử dụng Consumerthành phần là một cách hay để truy cập vào ngữ cảnh trong renderphương thức, trong đó kiểu của nó được suy ra một cách chính xác.

Thuộc contexttính có thể được sử dụng trong các phương thức vòng đời khác để truy cập vào ngữ cảnh. Chúng ta cần xác định rõ ràng chú thích kiểu cho thuộc contexttính và chỉ định ngữ cảnh cụ thể trong contextTypethuộc tính tĩnh.

Trong bài đăng tiếp theo, chúng ta sẽ tìm hiểu về cách tạo ngữ cảnh mà không cần phải truyền giá trị mặc định rồi thực hiện bất kỳ undefinedkiểm tra nào khi sử dụng ngữ cảnh đó.

Last updated

Was this helpful?