🚑 fix: resolve React hooks order violation in pagination components

Fix "Rendered fewer hooks than expected" error caused by conditional hook calls
in createCardProPagination function. The issue occurred when paginationArea was
commented out, breaking React's hooks rules.

**Problem:**
- createCardProPagination() internally called useIsMobile() hook
- When paginationArea was disabled, the hook was not called
- This violated React's rule that hooks must be called in the same order on every render

**Solution:**
- Refactor createCardProPagination to accept isMobile as a parameter
- Move useIsMobile() hook calls to component level
- Ensure consistent hook call order regardless of pagination usage

**Changes:**
- Update createCardProPagination function to accept isMobile parameter
- Add useIsMobile hook calls to all table components
- Pass isMobile parameter to createCardProPagination in all usage locations

**Files modified:**
- web/src/helpers/utils.js
- web/src/components/table/channels/index.jsx
- web/src/components/table/redemptions/index.jsx
- web/src/components/table/usage-logs/index.jsx
- web/src/components/table/tokens/index.jsx
- web/src/components/table/users/index.jsx
- web/src/components/table/mj-logs/index.jsx
- web/src/components/table/task-logs/index.jsx

Fixes critical runtime error and ensures stable pagination behavior across all table components.
This commit is contained in:
t0ng7u
2025-07-20 11:24:04 +08:00
parent 818e34682c
commit 805464e406
8 changed files with 23 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ import ChannelsActions from './ChannelsActions.jsx';
import ChannelsFilters from './ChannelsFilters.jsx';
import ChannelsTabs from './ChannelsTabs.jsx';
import { useChannelsData } from '../../../hooks/channels/useChannelsData.js';
import { useIsMobile } from '../../../hooks/common/useIsMobile.js';
import BatchTagModal from './modals/BatchTagModal.jsx';
import ModelTestModal from './modals/ModelTestModal.jsx';
import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx';
@@ -33,6 +34,7 @@ import { createCardProPagination } from '../../../helpers/utils';
const ChannelsPage = () => {
const channelsData = useChannelsData();
const isMobile = useIsMobile();
return (
<>
@@ -65,6 +67,7 @@ const ChannelsPage = () => {
total: channelsData.channelCount,
onPageChange: channelsData.handlePageChange,
onPageSizeChange: channelsData.handlePageSizeChange,
isMobile: isMobile,
})}
t={channelsData.t}
>

View File

@@ -26,10 +26,12 @@ import MjLogsFilters from './MjLogsFilters.jsx';
import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx';
import ContentModal from './modals/ContentModal.jsx';
import { useMjLogsData } from '../../../hooks/mj-logs/useMjLogsData.js';
import { useIsMobile } from '../../../hooks/common/useIsMobile.js';
import { createCardProPagination } from '../../../helpers/utils';
const MjLogsPage = () => {
const mjLogsData = useMjLogsData();
const isMobile = useIsMobile();
return (
<>
@@ -48,6 +50,7 @@ const MjLogsPage = () => {
total: mjLogsData.logCount,
onPageChange: mjLogsData.handlePageChange,
onPageSizeChange: mjLogsData.handlePageSizeChange,
isMobile: isMobile,
})}
t={mjLogsData.t}
>

View File

@@ -25,10 +25,12 @@ import RedemptionsFilters from './RedemptionsFilters.jsx';
import RedemptionsDescription from './RedemptionsDescription.jsx';
import EditRedemptionModal from './modals/EditRedemptionModal';
import { useRedemptionsData } from '../../../hooks/redemptions/useRedemptionsData';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
import { createCardProPagination } from '../../../helpers/utils';
const RedemptionsPage = () => {
const redemptionsData = useRedemptionsData();
const isMobile = useIsMobile();
const {
// Edit state
@@ -106,6 +108,7 @@ const RedemptionsPage = () => {
total: redemptionsData.tokenCount,
onPageChange: redemptionsData.handlePageChange,
onPageSizeChange: redemptionsData.handlePageSizeChange,
isMobile: isMobile,
})}
t={t}
>

View File

@@ -26,10 +26,12 @@ import TaskLogsFilters from './TaskLogsFilters.jsx';
import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx';
import ContentModal from './modals/ContentModal.jsx';
import { useTaskLogsData } from '../../../hooks/task-logs/useTaskLogsData.js';
import { useIsMobile } from '../../../hooks/common/useIsMobile.js';
import { createCardProPagination } from '../../../helpers/utils';
const TaskLogsPage = () => {
const taskLogsData = useTaskLogsData();
const isMobile = useIsMobile();
return (
<>
@@ -48,6 +50,7 @@ const TaskLogsPage = () => {
total: taskLogsData.logCount,
onPageChange: taskLogsData.handlePageChange,
onPageSizeChange: taskLogsData.handlePageSizeChange,
isMobile: isMobile,
})}
t={taskLogsData.t}
>

View File

@@ -25,10 +25,12 @@ import TokensFilters from './TokensFilters.jsx';
import TokensDescription from './TokensDescription.jsx';
import EditTokenModal from './modals/EditTokenModal';
import { useTokensData } from '../../../hooks/tokens/useTokensData';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
import { createCardProPagination } from '../../../helpers/utils';
const TokensPage = () => {
const tokensData = useTokensData();
const isMobile = useIsMobile();
const {
// Edit state
@@ -108,6 +110,7 @@ const TokensPage = () => {
total: tokensData.tokenCount,
onPageChange: tokensData.handlePageChange,
onPageSizeChange: tokensData.handlePageSizeChange,
isMobile: isMobile,
})}
t={t}
>

View File

@@ -25,10 +25,12 @@ import LogsFilters from './UsageLogsFilters.jsx';
import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx';
import UserInfoModal from './modals/UserInfoModal.jsx';
import { useLogsData } from '../../../hooks/usage-logs/useUsageLogsData.js';
import { useIsMobile } from '../../../hooks/common/useIsMobile.js';
import { createCardProPagination } from '../../../helpers/utils';
const LogsPage = () => {
const logsData = useLogsData();
const isMobile = useIsMobile();
return (
<>
@@ -47,6 +49,7 @@ const LogsPage = () => {
total: logsData.logCount,
onPageChange: logsData.handlePageChange,
onPageSizeChange: logsData.handlePageSizeChange,
isMobile: isMobile,
})}
t={logsData.t}
>

View File

@@ -26,10 +26,12 @@ import UsersDescription from './UsersDescription.jsx';
import AddUserModal from './modals/AddUserModal.jsx';
import EditUserModal from './modals/EditUserModal.jsx';
import { useUsersData } from '../../../hooks/users/useUsersData';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
import { createCardProPagination } from '../../../helpers/utils';
const UsersPage = () => {
const usersData = useUsersData();
const isMobile = useIsMobile();
const {
// Modal state
@@ -111,6 +113,7 @@ const UsersPage = () => {
total: usersData.userCount,
onPageChange: usersData.handlePageChange,
onPageSizeChange: usersData.handlePageSizeChange,
isMobile: isMobile,
})}
t={t}
>

View File

@@ -24,7 +24,6 @@ import { toast } from 'react-toastify';
import { THINK_TAG_REGEX, MESSAGE_ROLES } from '../constants/playground.constants';
import { TABLE_COMPACT_MODES_KEY } from '../constants';
import { MOBILE_BREAKPOINT } from '../hooks/common/useIsMobile.js';
import { useIsMobile } from '../hooks/common/useIsMobile.js';
const HTMLToastContent = ({ htmlContent }) => {
return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
@@ -570,7 +569,7 @@ export const modelSelectFilter = (input, option) => {
};
// -------------------------------
// CardPro 分页配置组件
// CardPro 分页配置函数
// 用于创建 CardPro 的 paginationArea 配置
export const createCardProPagination = ({
currentPage,
@@ -578,11 +577,10 @@ export const createCardProPagination = ({
total,
onPageChange,
onPageSizeChange,
isMobile = false,
pageSizeOpts = [10, 20, 50, 100],
showSizeChanger = true,
}) => {
const isMobile = useIsMobile();
if (!total || total <= 0) return null;
return (