开源日报每天推荐一个 GitHub 优质开源项目和一篇精选英文科技或编程文章原文,坚持阅读《开源日报》,保持每日学习的好习惯。


2024年1月7日,开源日报第1067期:
今日推荐开源项目:《crewAI》
今日推荐英文原文:《Future-proof Your Components With This Game Changing React Pattern》



开源项目

今日推荐开源项目:《crewAI》传送门:项目链接

推荐理由:CrewAI🤖是用于编排角色扮演、自主AI代理的尖端框架。通过培养协作智能,使智能体能够无缝协作,处理复杂的任务


英文原文

今日推荐英文原文:Future-proof Your Components With This Game Changing React Pattern

推荐理由:JavaScript中的Singleton模式通过创建全局唯一实例来管理应用程序的全局状态, 但是Singleton在JavaScript中被认为是反模式,Redux或React Context更常用于React中的全局状态管理


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/