From 8db2d86131d8330f5f13412eff47b53e9f54267f Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Tue, 22 Oct 2024 17:18:55 +0800 Subject: [PATCH 1/3] chore: remove useNewSubscriptionData manual updateTenant --- .../use-new-subscription-data.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts index c355a143422..941aa785fef 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts +++ b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts @@ -1,5 +1,5 @@ -import { cond, condString, pick } from '@silverhand/essentials'; -import { useContext, useEffect, useMemo } from 'react'; +import { cond, condString } from '@silverhand/essentials'; +import { useContext, useMemo } from 'react'; import useSWR from 'swr'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; @@ -50,13 +50,7 @@ const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolea [currentTenant?.planId, logtoSkus] ); - useEffect(() => { - if (subscriptionUsageData?.quota) { - updateTenant(tenantId, { - quota: pick(subscriptionUsageData.quota, 'mauLimit', 'tokenLimit'), - }); - } - }, [tenantId, subscriptionUsageData?.quota, updateTenant]); + // TODO: @darcyYe can use `updateTenant()` to manually update the quota of the current tenant. Previously we removed such logic to unblock the release since it breaks the Cloud console integration tests. return useMemo( () => ({ From f73304893142c0f9f453d81c0eaf45598854e47e Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Wed, 23 Oct 2024 01:53:04 +0800 Subject: [PATCH 2/3] fix: fix hook dependency list to avoid inf loop --- .../use-new-subscription-data.ts | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts index 941aa785fef..d83e21484fe 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts +++ b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts @@ -1,5 +1,5 @@ -import { cond, condString } from '@silverhand/essentials'; -import { useContext, useMemo } from 'react'; +import { cond, pick } from '@silverhand/essentials'; +import { useContext, useEffect, useMemo } from 'react'; import useSWR from 'swr'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; @@ -21,25 +21,24 @@ import { type NewSubscriptionContext } from './types'; const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolean } = () => { const cloudApi = useCloudApi(); - const { currentTenant, updateTenant } = useContext(TenantsContext); + const { currentTenant, currentTenantId, updateTenant } = useContext(TenantsContext); const { isLoading: isLogtoSkusLoading, data: fetchedLogtoSkus } = useLogtoSkus(); - const tenantId = condString(currentTenant?.id); const { data: currentSubscription, isLoading: isSubscriptionLoading, mutate: mutateSubscription, - } = useSubscription(tenantId); + } = useSubscription(currentTenantId); const { data: subscriptionUsageData, isLoading: isSubscriptionUsageDataLoading, mutate: mutateSubscriptionQuotaAndUsages, } = useSWR( - isCloud && tenantId && `/api/tenants/${tenantId}/subscription-usage`, + isCloud && currentTenantId && `/api/tenants/${currentTenantId}/subscription-usage`, async () => cloudApi.get('/api/tenants/:tenantId/subscription-usage', { - params: { tenantId }, + params: { tenantId: currentTenantId }, }) ); @@ -50,7 +49,16 @@ const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolea [currentTenant?.planId, logtoSkus] ); - // TODO: @darcyYe can use `updateTenant()` to manually update the quota of the current tenant. Previously we removed such logic to unblock the release since it breaks the Cloud console integration tests. + useEffect(() => { + if (subscriptionUsageData?.quota) { + updateTenant(currentTenantId, { + quota: pick(subscriptionUsageData.quota, 'mauLimit', 'tokenLimit'), + }); + } + // Since `updateTenant` updates `tenants` in TenantsContext and triggers re-renders (`updateTenant` is re-rendered as well), + // we can not add `updateTenant` to the dependency list, otherwise it will cause a infinite loop. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentTenantId, subscriptionUsageData?.quota]); return useMemo( () => ({ From 3164bb6f16b776563298eba79ccbf6d4b61e755c Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Wed, 23 Oct 2024 11:05:48 +0800 Subject: [PATCH 3/3] refactor: wrap TenantsContext methods with useCallback --- .../use-new-subscription-data.ts | 5 +- .../console/src/contexts/TenantsProvider.tsx | 50 +++++++++++++------ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts index d83e21484fe..ab71e62c2cd 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts +++ b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts @@ -55,10 +55,7 @@ const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolea quota: pick(subscriptionUsageData.quota, 'mauLimit', 'tokenLimit'), }); } - // Since `updateTenant` updates `tenants` in TenantsContext and triggers re-renders (`updateTenant` is re-rendered as well), - // we can not add `updateTenant` to the dependency list, otherwise it will cause a infinite loop. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentTenantId, subscriptionUsageData?.quota]); + }, [currentTenantId, subscriptionUsageData?.quota, updateTenant]); return useMemo( () => ({ diff --git a/packages/console/src/contexts/TenantsProvider.tsx b/packages/console/src/contexts/TenantsProvider.tsx index 419045a3fd5..04fe0d02e59 100644 --- a/packages/console/src/contexts/TenantsProvider.tsx +++ b/packages/console/src/contexts/TenantsProvider.tsx @@ -118,31 +118,49 @@ function TenantsProvider({ children }: Props) { [currentTenantId, tenants] ); + const resetTenants = useCallback((tenants: TenantResponse[]) => { + setTenants(tenants); + setIsInitComplete(true); + }, []); + + const prependTenant = useCallback((tenant: TenantResponse) => { + setTenants((tenants) => [tenant, ...tenants]); + }, []); + + const removeTenant = useCallback((tenantId: string) => { + setTenants((tenants) => tenants.filter((tenant) => tenant.id !== tenantId)); + }, []); + + const updateTenant = useCallback((tenantId: string, data: Partial) => { + setTenants((tenants) => + tenants.map((tenant) => (tenant.id === tenantId ? { ...tenant, ...data } : tenant)) + ); + }, []); + const memorizedContext = useMemo( () => ({ tenants, - resetTenants: (tenants: TenantResponse[]) => { - setTenants(tenants); - setIsInitComplete(true); - }, - prependTenant: (tenant: TenantResponse) => { - setTenants((tenants) => [tenant, ...tenants]); - }, - removeTenant: (tenantId: string) => { - setTenants((tenants) => tenants.filter((tenant) => tenant.id !== tenantId)); - }, - updateTenant: (tenantId: string, data: Partial) => { - setTenants((tenants) => - tenants.map((tenant) => (tenant.id === tenantId ? { ...tenant, ...data } : tenant)) - ); - }, + resetTenants, + prependTenant, + removeTenant, + updateTenant, isInitComplete, currentTenantId, isDevTenant: currentTenant?.tag === TenantTag.Development, currentTenant, navigateTenant, }), - [currentTenant, currentTenantId, isInitComplete, navigateTenant, tenants] + [ + currentTenant, + currentTenantId, + isInitComplete, + navigateTenant, + tenants, + resetTenants, + prependTenant, + removeTenant, + updateTenant, + ] ); return {children};