开源日报每天推荐一个 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/