開源日報每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,堅持閱讀《開源日報》,保持每日學習的好習慣。

2024年1月6日,開源日報第1066期:
今日推薦開源項目:《GitHub-Chinese-Top-Charts》
今日推薦英文原文:《Future-proof Your Components With This Game Changing React Pattern》


開源項目

今日推薦開源項目:《GitHub-Chinese-Top-Charts》傳送門:項目鏈接

推薦理由:🇨🇳 GitHub中文排行榜,各語言分設「軟體 | 資料」榜單,精準定位中文好項目。各取所需,高效學習


英文原文

今日推薦英文原文:React Query is the best thing that happened to React

推薦理由:文章主要介紹了一種名為"headless component pattern"的React模式,該模式的核心思想是將組件的業務邏輯與UI部分分離,使得UI的更新可以在不影響業務邏輯的情況下進行。文章提供了一個簡單的例子,展示了如何使用這一模式創建一個下拉菜單組件


Future-proof Your Components With This Game Changing React Pattern

Software development is a non-stop ongoing process. The biggest challenge in the process is maintainability. When new features and improvements start to add up, it results in more code being added to be maintained.

Today we are going to explore a simple pattern in React which allows building future-proof components. The goal is to make those components easily adapt to future changes while keeping the business logic separate from the UI code.

How does it work?

The core of this pattern is to separate the business logic from the UI part of the component itself. This makes the UI part of the code decoupled from business logic. When the UI needs to be updated in the future, it can be done without touching the business logic code.

The pattern which we are going to use is called the headless component pattern. In this pattern a component is implemented as React hooks. This component is responsible for the logic and state management. The headless component does not know anything about the UI. A separate component is built which is responsible only for the UI and integrates the first component for state and logic. The pattern is used by many popular React component libraries like: DownShift, React Table etc.

Your first future-proof component

Let』s start with writing the first React component using this pattern.

Below is an example of a drop-down headless component:

const useDropdown = (items: Item[]) => {
  // ... state variables ..
  const [selectedIndex, setSelectedIndex] = useState<number>(-1);
  const [isOpen, setIsOpen] = useState(false);
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  // helper function can return some aria attribute for UI
  const getAriaAttributes = () => ({
    role: "combobox",
    "aria-expanded": isOpen,
    "aria-activedescendant": selectedItem ? selectedItem.text : undefined,
  });

  const handleKeyDown = (e: React.KeyboardEvent) => {
    // ... switch statement ...
  };

  const toggleDropdown = () => setIsOpen((isOpen) => !isOpen);

  return {
    isOpen,
    toggleDropdown,
    handleKeyDown,
    selectedItem,
    setSelectedItem,
    selectedIndex,
  };
};

Let』s integrate our headless component with the component responsible for handling UIs:

const Dropdown = ({ items }: DropdownProps) => {
  const {
    isOpen,
    selectedItem,
    selectedIndex,
    toggleDropdown,
    handleKeyDown,
    setSelectedItem,
  } = useDropdown(items);

  return (
    <div className="dropdown" onKeyDown={handleKeyDown}>
      <Trigger
        onClick={toggleDropdown}
        label={selectedItem ? selectedItem.text : "Select an item..."}
      />
      {isOpen && (
        <DropdownMenu
          items={items}
          onItemClick={setSelectedItem}
          selectedIndex={selectedIndex}
        />
      )}
    </div>
  );
};

Above is a very basic example of a headless component. Imagine the possibility when the same pattern is integrated with more complex applications. The headless component pattern is extremely powerful when it comes to building future-proof highly extensible components.

When to use this pattern?

The magic of this pattern comes handy when building a large application that changes frequently. Implementing this pattern not only transforms React components to highly extensible but it also makes them very maintainable in a large codebase.


下載開源日報APP:https://openingsource.org/2579/
加入我們:https://openingsource.org/about/join/
關注我們:https://openingsource.org/about/love/