用好PrimeReact组件库提升前端开发效率

IT人东润 框架 阅读 1,811
赞 23 收藏
二维码
手机扫码查看
反馈

先来个登录表单,看看这玩意儿咋用

我最近在搞一个管理后台,UI 框架选了 PrimeReact,主要是老板说要“看起来专业点”,又不想花时间自己写样式。于是我就上了 PrimeReact,结果第一关就卡在登录页——看着文档一堆组件,但真动手写的时候还是得查半天。

用好PrimeReact组件库提升前端开发效率

直接上代码,别整那些虚的:

import React, { useState } from 'react';
import { InputText } from 'primereact/inputtext';
import { Password } from 'primereact/password';
import { Button } from 'primereact/button';
import { Card } from 'primereact/card';

const LoginForm = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('登录数据:', { username, password });
    // 实际项目里这里会调 API
    fetch('https://jztheme.com/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password })
    });
  };

  return (
    <Card title="管理员登录" style={{ width: '30rem', margin: '2rem auto' }}>
      <form onSubmit={handleSubmit}>
        <div className="p-field">
          <label htmlFor="username">用户名</label>
          <InputText
            id="username"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
            placeholder="请输入用户名"
            required
          />
        </div>
        <div className="p-field mt-3">
          <label htmlFor="password">密码</label>
          <Password
            id="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            toggleMask
            feedback={false}
            placeholder="请输入密码"
            required
          />
        </div>
        <Button label="登录" type="submit" className="mt-4 w-full" />
      </form>
    </Card>
  );
};

export default LoginForm;

注意看 Password 组件的两个属性:toggleMask 是那个小眼睛图标,可以切明文密码;feedback={false} 是我特意关掉的,因为默认它会显示强度提示,但在登录页这玩意儿纯属干扰。

主题切换?别信文档,我折腾了三个小时

PrimeReact 的主题系统一开始把我绕晕了。你以为改个 CSS 变量就行?错。你得先引入对应的 CSS 文件,比如你要用 Saga 蓝色主题,必须在 index.jsApp.css 顶部加上:

@import "primereact/resources/themes/saga-blue/theme.css";
@import "primereact/resources/primereact.min.css";
@import "primeicons/primeicons.css";

我当时傻乎乎只改了变量,页面一点反应都没有,查了一堆 GitHub issue 才发现是这个顺序问题:theme.css 必须在 primereact.min.css 前面导入,否则样式会被覆盖。亲测有效顺序如下:

  • 先导入 theme.css
  • 再导入 primereact.min.css
  • 最后是 icon 字体

如果你还想自定义颜色,比如把主色调改成你们公司的品牌蓝,可以用 CSS 变量覆盖:

:root {
  --primary-color: #1877f2;
  --surface-ground: #f8f9fa;
}

但这招不是万能的,有些组件内部写死了颜色值,就得用 !important 强行覆盖,虽然难看但能解决问题。

表格分页和筛选,这才是重头戏

大多数管理后台的核心就是表格。我用 DataTable 配合 Paginator 和后端接口对接,踩了好几个坑,现在把稳定方案贴出来。

import React, { useState, useEffect } from 'react';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Paginator } from 'primereact/paginator';

const UserList = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [totalRecords, setTotalRecords] = useState(0);
  const [page, setPage] = useState(0);
  const [rows, setRows] = useState(10);

  const fetchUsers = async (page = 0, size = 10) => {
    setLoading(true);
    try {
      const res = await fetch(https://jztheme.com/api/users?page=${page}&amp;size=${size});
      const data = await res.json();
      setUsers(data.items);
      setTotalRecords(data.total);
    } catch (err) {
      console.error('获取用户失败:', err);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchUsers(page, rows);
  }, [page, rows]);

  const onPageChange = (event) => {
    setPage(event.first / event.rows);
    setRows(event.rows);
  };

  return (
    <div>
      <DataTable
        value={users}
        loading={loading}
        tableStyle={{ minWidth: '60rem' }}
      >
        <Column field="id" header="ID" sortable />
        <Column field="name" header="姓名" />
        <Column field="email" header="邮箱" />
        <Column field="role" header="角色" />
      </DataTable>
      <Paginator
        first={page * rows}
        rows={rows}
        totalRecords={totalRecords}
        onPageChange={onPageChange}
        rowsPerPageOptions={[5, 10, 20]}
      />
    </div>
  );
};

export default UserList;

重点来了:我最开始把 first 直接传 page,结果翻页直接乱掉。后来发现 Paginatorfirst 是从 0 开始的偏移量,不是页码。所以得算成 page * rows,不然第二页就跳到第 10 条之后去了。

还有个小技巧:如果某个字段需要自定义渲染,比如状态列要显示不同颜色标签,可以用 body 属性:

const statusBodyTemplate = (rowData) => {
  const color = rowData.status === 'active' ? 'green' : 'gray';
  return <span style={{ color }}>{rowData.status}</span>;
};

// 然后在 Column 里:
<Column field="status" header="状态" body={statusBodyTemplate} />

踩坑提醒:这三点一定注意

用了两周 PrimeReact,总结三个最容易出问题的地方:

  • 不要忘记安装 primeicons:很多组件依赖图标库,装完 PrimeReact 得顺手加一句 npm install primeicons,不然小图标全变成方块。
  • TreeTable 性能差到离谱:如果你的数据超过 500 行,别用 TreeTable,加载直接卡死。建议自己用普通 Table + 展开行实现,或者考虑虚拟滚动方案。
  • SSR 下容易样式错乱:Next.js 项目里做服务端渲染时,记得在 _document.js 中正确注入 CSS,否则首屏会闪一下没样式的界面。官方有个 PrimeReact.ripple 也要手动开启。

还有一个玄学问题:有时候热更新后样式丢了,刷新也没用,只能重启 dev server。目前没找到根因,临时方案是删 node_modules/.vite 缓存。

高级玩法:把 Dialog 当成通用弹窗用

我一直不喜欢每个弹窗都单独维护一个 visible 状态,太啰嗦。后来我搞了个通用 Dialog Hook,所有确认框、表单弹窗都能复用。

// useDialog.js
import { useState } from 'react';

export const useDialog = () => {
  const [config, setConfig] = useState(null);

  const open = (content, options = {}) => {
    setConfig({ content, ...options });
  };

  const close = () => setConfig(null);

  return { dialog: config, open, close };
};

然后在 App 级别挂一个全局弹窗监听器:

// App.js
import { Dialog } from 'primereact/dialog';
import { useDialog } from './hooks/useDialog';

const App = () => {
  const { dialog, close } = useDialog();

  return (
    <>
      {/* 其他内容 */}
      {dialog && (
        <Dialog
          visible={true}
          onHide={close}
          header={dialog.header || '提示'}
          style={dialog.style}
        >
          {dialog.content}
        </Dialog>
      )}
    </>
  );
};

调用的时候就很清爽:

// 在某个按钮点击事件里
const handleClick = () => {
  open(
    <div>
      <p>确定要删除这条记录吗?</p>
      <Button label="取消" onClick={close} text />
      <Button label="确认" severity="danger" onClick={handleDelete} />
    </div>,
    { header: '警告', style: { width: '20rem' } }
  );
};

虽然这不是 PrimeReact 官方推荐做法,但它解决了状态分散的问题。缺点是多个弹窗不能叠加,但我们项目里也没这需求,够用就行。

结语

以上是我踩坑后的总结,希望对你有帮助。PrimeReact 功能确实全,但文档写得跟说明书一样,很多细节得自己试才能明白。这个技巧的拓展用法还有很多,比如结合 Formik 做复杂表单验证,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流,我现在也还在边改 bug 边学习。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论