我开源了一个 React 组件库,沉淀了多个高频组件和实用 Hooks

我开源了一个 React 组件库,沉淀了多个高频组件和实用 Hooks

大家好,我是木木剑光。

在业务开发过程中,我们经常会遇到一些重复性的需求和场景。比如瀑布流布局、无限滚动加载、竞态请求处理等等。每次都要重新写一遍类似的逻辑,不仅浪费时间,还容易出现 bug。

为了解决这个问题,我将团队在研发过程中沉淀下来的一些通用组件和 Hooks 整理成了一个开源组件库 ------ @mmjg/ui-components。今天想和大家分享一下这个库的设计思路和核心功能。

项目背景

在实际的业务场景中,我们发现有几类需求特别高频:

  1. 瀑布流布局:图片展示、商品列表等场景,需要高性能的虚拟滚动和响应式布局
  2. 3D 交互效果:一些创新性的 UI 交互,比如 3D 旋转菜单
  3. 流光效果:loading 状态的视觉优化
  4. 通用 Hooks:无限加载、元素尺寸监听、竞态请求处理等

这些需求看似简单,但要做得好、做得通用,还是有不少细节需要考虑的。比如瀑布流组件,需要考虑虚拟滚动性能、响应式布局、动态高度计算、滚动位置恢复等等。

核心组件介绍

1. Masonry 瀑布流组件

瀑布流布局在前端开发中非常常见,但要实现一个高性能、功能完善的瀑布流组件并不容易。我们的 Masonry 组件具有以下特性:

核心功能:

  • 虚拟滚动优化:只渲染可视区域内的元素,大幅提升性能
  • 响应式布局:支持断点配置,根据容器宽度自动调整列数
  • 无限加载:内置加载更多机制,支持阈值配置
  • 动态高度计算:自动计算每个 item 的高度,支持最小高度和额外高度配置
  • 滚动控制:支持滚动到顶部、滚动到指定元素等 API

关键实现原理:

虚拟滚动的核心思路是:计算可视区域的范围,只渲染这个范围内的元素。我们通过 useScrollViewArea hook 来实现:

typescript 复制代码
const [viewRange, reCalcViewRange] = useScrollViewArea({
    container: () => containerRef.current!,
    overscanHeight: 3000, // 预渲染区域
    loadMoreThreshold,
    onLoadMore,
});

这样,即使有成千上万条数据,也能保持流畅的滚动性能。

使用示例:

typescript 复制代码
import { Masonry } from '@mmjg/ui-components';

<Masonry
    items={images}
    columnCount={4}
    gap={8}
    itemRender={({ item, columnWidth, height }) => (
        <img
            src={item.src}
            style={{ width: columnWidth, height }}
        />
    )}
    onLoadMore={(check) => {
        // 加载更多数据
        loadMoreData().then(() => {
            check(); // 检查是否需要继续加载
        });
    }}
/>

这是一个创新的 3D 旋转菜单组件,支持鼠标拖拽交互。它的实现原理是通过 CSS 3D transform 和自定义 hook 实现的。

核心思路:

  1. 使用 rotateYtranslateZ 将菜单项分布在 3D 空间中
  2. 通过 useRotateAnimation hook 管理旋转动画
  3. 通过 useMouseDragOffset hook 处理鼠标拖拽交互
typescript 复制代码
export function Menu3D(props: Menu3DProps) {
    const { menus, rotateRadius = 200 } = props;
    const itemRotateDeg = 360 / menus.length;

    return (
        <div className={styles["component-menu3d"]}>
            <div className={styles["component-menu3d-rotate"]}>
                {menus.map((menu, index) => (
                    <div
                        key={menu.id}
                        style={{
                            transform: `rotateY(${itemRotateDeg * index}deg)
                                       translateZ(${rotateRadius}px)`
                        }}
                        onClick={() => onMenuClick(menu.id)}
                    >
                        {/* 菜单内容 */}
                    </div>
                ))}
            </div>
        </div>
    );
}

3. Shimmer 流光效果组件

这是一个简单但实用的流光效果组件,支持文本和容器两种模式。

typescript 复制代码
<Shimmer type="text" duration={2}>
    加载中...
</Shimmer>

<Shimmer type="container" width={10} color="#ffffff">
    <div style={{ width: 200, height: 100 }}>
        内容区域
    </div>
</Shimmer>

实用 Hooks 集合

除了 UI 组件,我们还沉淀了一些高频使用的 Hooks。

useAutoLoadMore:自动加载更多

这是一个解决无限加载场景痛点的 hook。

问题场景: 分页的 pageNum 是一个定值,但窗口的大小用户可以自由拖拽,因此可能出现窗口被拖拽得较大的情况下,滚动条消失,导致用户无法触发加载更多。

解决方案: 监听滚动容器大小变化,当滚动容器滚动条消失时,如果还有更多则触发加载更多。

typescript 复制代码
useAutoLoadMore(containerRef.current, {
    hasMore: hasMoreData,
    onLoadMore: (check) => {
        loadMoreData().then(() => {
            check(); // 检查是否需要继续加载
        });
    }
});

useBoxSizeObserver:监听元素尺寸

基于 ResizeObserver 实现的 hook,可以方便地监听元素尺寸变化。

typescript 复制代码
const [ref, boxSize] = useBoxSizeObserver();

return (
    <div ref={ref}>
        宽度: {boxSize.width}, 高度: {boxSize.height}
    </div>
);

UniqueRequest:竞态请求处理

这是一个通用模块,用于解决前端开发中常见的竞态问题。

问题场景: 在搜索场景中,用户快速输入时可能会发起多个请求,后面的请求可能先返回,导致显示的结果不是最新的。

解决方案: 使用 AbortController 取消之前的请求,只保留最新的请求结果。

typescript 复制代码
const uniqueRequest = new UniqueRequest();

// 在搜索场景中使用
const handleSearch = async (keyword: string) => {
    try {
        const result = await uniqueRequest.request(
            searchAPI,
            { keyword }
        );
        setSearchResult(result);
    } catch (error) {
        if (isAbortError(error)) {
            // 请求被取消,不做处理
            return;
        }
        // 处理其他错误
    }
};

技术栈和工程化

这个组件库基于以下技术栈:

  • React 18+:使用稳定的 React 特性
  • TypeScript:完整的类型支持
  • Rolldown:使用下一代打包工具,构建速度更快
  • Less:样式解决方案

在工程化方面,我们做了以下考虑:

  1. 类型安全:所有组件和 hooks 都有完整的 TypeScript 类型定义
  2. Tree Shaking:支持按需引入,减少打包体积
  3. 开发体验:支持 development 和 production 两种模式,开发时直接引用源码,生产环境使用构建产物

使用方式

组件库已经发布到 npm,可以直接安装使用:

bash 复制代码
pnpm add @mmjg/ui-components

更多详尽的使用指南请查看我们的官方文档

总结

@mmjg/ui-components 是我们在实际业务开发中沉淀下来的组件库,它解决了我们遇到的一些常见问题。虽然目前功能还不够完善,但我们会持续迭代和优化。

开源这个项目的目的,一方面是希望能帮助到有同样需求的开发者,另一方面也希望能收到社区的反馈,让这个库变得更好。

如果你对这个项目感兴趣,欢迎查看我们的文档源码,也欢迎提出 Issue 和 PR。


相关链接:

相关推荐
晴天161 小时前
Chrome DevTools 深度调试指南
前端·chrome·chrome devtools
林冠宏_指尖下的幽灵1 小时前
AI发展下的后编程时代思考
前端·人工智能·后端
_山海2 小时前
Bun入门指南
前端·javascript·后端
想睡懒觉2 小时前
我用 CSS 3D 做了个星空隧道 Loading,没有 Three.js
前端
labixiong2 小时前
transition 写在 CSS 变量上为什么不生效?给变量补张「类型身份证」
前端·css·html
YHL2 小时前
🧠 Agent 记忆进阶:总结压缩与向量检索 —— 从截断到 Milvus 长期记忆
前端·人工智能
YHL2 小时前
🎯 JavaScript 单例模式(Singleton Pattern)—— 从理论到实战
javascript·设计模式
用户921080262862 小时前
前端 Vue 专栏 05:从 Object.defineProperty 到 Proxy,彻底理解 Vue 响应式原理
前端
Fluxart.ai3 小时前
GPT Image 2.5 有使用次数限制吗?额度、并发、频率限制说明
服务器·前端·gpt