開源日報每天推薦一個 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/