diff --git a/packages/react-query/CHANGELOG.md b/packages/react-query/CHANGELOG.md
index d286e9029..9e4a9a6b8 100644
--- a/packages/react-query/CHANGELOG.md
+++ b/packages/react-query/CHANGELOG.md
@@ -1,5 +1,12 @@
# @suspensive/react-query
+## 1.17.4
+
+### Patch Changes
+
+- Updated dependencies [70d8128]
+ - @suspensive/react@1.17.4
+
## 1.17.3
### Patch Changes
diff --git a/packages/react-query/package.json b/packages/react-query/package.json
index db4afe225..ac6340efe 100644
--- a/packages/react-query/package.json
+++ b/packages/react-query/package.json
@@ -1,6 +1,6 @@
{
"name": "@suspensive/react-query",
- "version": "1.17.3",
+ "version": "1.17.4",
"description": "Useful helpers for @tanstack/react-query with suspense",
"keywords": [
"suspensive",
@@ -70,7 +70,7 @@
"tsd": "^0.28.1"
},
"peerDependencies": {
- "@suspensive/react": "workspace:^1.17.3",
+ "@suspensive/react": "workspace:^1.17.4",
"@tanstack/react-query": "^4",
"react": "^16.8 || ^17 || ^18"
},
diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md
index 7acddd431..9286f1415 100644
--- a/packages/react/CHANGELOG.md
+++ b/packages/react/CHANGELOG.md
@@ -1,5 +1,11 @@
# @suspensive/react
+## 1.17.4
+
+### Patch Changes
+
+- 70d8128: fix(react): convert Suspense.CSROnly's useEffect into useIsomorphicLayoutEffect to prevent unnecessary layout shift
+
## 1.17.3
### Patch Changes
diff --git a/packages/react/package.json b/packages/react/package.json
index 3274a4a79..a3f1b981b 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -1,6 +1,6 @@
{
"name": "@suspensive/react",
- "version": "1.17.3",
+ "version": "1.17.4",
"description": "Useful interfaces for React Suspense",
"keywords": [
"suspensive",
diff --git a/packages/react/src/Suspense.tsx b/packages/react/src/Suspense.tsx
index 0a5ca8f10..9d1a998bb 100644
--- a/packages/react/src/Suspense.tsx
+++ b/packages/react/src/Suspense.tsx
@@ -1,6 +1,6 @@
import type { ComponentProps, ComponentType, ReactNode, SuspenseProps as ReactSuspenseProps } from 'react'
import { Suspense as ReactSuspense, createContext, useContext } from 'react'
-import { useIsMounted } from './hooks'
+import { useIsClient } from './hooks'
import type { PropsWithoutChildren } from './types'
export type SuspenseProps = ReactSuspenseProps
@@ -21,10 +21,10 @@ if (process.env.NODE_ENV !== 'production') {
DefaultSuspense.displayName = 'Suspense'
}
const CSROnlySuspense = (props: SuspenseProps) => {
- const isMounted = useIsMounted()
+ const isClient = useIsClient()
const fallback = useFallbackWithContext(props.fallback)
- return isMounted ? : <>{fallback}>
+ return isClient ? : <>{fallback}>
}
if (process.env.NODE_ENV !== 'production') {
CSROnlySuspense.displayName = 'Suspense.CSROnly'
diff --git a/packages/react/src/hooks/index.ts b/packages/react/src/hooks/index.ts
index 5e354cd50..825ac85ad 100644
--- a/packages/react/src/hooks/index.ts
+++ b/packages/react/src/hooks/index.ts
@@ -1,5 +1,5 @@
export { useIsChanged } from './useIsChanged'
-export { useIsMounted } from './useIsMounted'
+export { useIsClient } from './useIsClient'
export { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
export { useKey } from './useKey'
export { usePrevious } from './usePrevious'
diff --git a/packages/react/src/hooks/useIsClient.spec.ts b/packages/react/src/hooks/useIsClient.spec.ts
new file mode 100644
index 000000000..ce705580b
--- /dev/null
+++ b/packages/react/src/hooks/useIsClient.spec.ts
@@ -0,0 +1,12 @@
+import { renderHook } from '@testing-library/react'
+import { useIsClient } from '.'
+
+describe('useIsClient', () => {
+ it('should return true when client side painting start', () => {
+ const {
+ result: { current: isClient },
+ } = renderHook(() => useIsClient())
+
+ expect(isClient).toBe(true)
+ })
+})
diff --git a/packages/react/src/hooks/useIsClient.ts b/packages/react/src/hooks/useIsClient.ts
new file mode 100644
index 000000000..3329a6390
--- /dev/null
+++ b/packages/react/src/hooks/useIsClient.ts
@@ -0,0 +1,12 @@
+import { useState } from 'react'
+import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
+
+export const useIsClient = () => {
+ const [isClient, setIsClient] = useState(false)
+
+ useIsomorphicLayoutEffect(() => {
+ setIsClient(true)
+ }, [])
+
+ return isClient
+}
diff --git a/packages/react/src/hooks/useIsMounted.spec.ts b/packages/react/src/hooks/useIsMounted.spec.ts
deleted file mode 100644
index 5954eaacb..000000000
--- a/packages/react/src/hooks/useIsMounted.spec.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { renderHook } from '@testing-library/react'
-import { useIsMounted } from '.'
-
-describe('useIsMounted', () => {
- it('should return true when component is mounted', () => {
- const {
- result: { current: isMounted },
- } = renderHook(() => useIsMounted())
-
- expect(isMounted).toBe(true)
- })
-})
diff --git a/packages/react/src/hooks/useIsMounted.ts b/packages/react/src/hooks/useIsMounted.ts
deleted file mode 100644
index 3ce612fe5..000000000
--- a/packages/react/src/hooks/useIsMounted.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useEffect, useState } from 'react'
-
-export const useIsMounted = () => {
- const [isMounted, setIsMounted] = useState(false)
-
- useEffect(() => {
- setIsMounted(true)
- }, [])
-
- return isMounted
-}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 52125b1ad..0a531f331 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -343,13 +343,13 @@ importers:
specifier: ^1.3.9
version: 1.3.9(@emotion/react@11.11.0)(react@18.2.0)
'@suspensive/react':
- specifier: workspace:1.17.3
+ specifier: workspace:1.17.4
version: link:../../packages/react
'@suspensive/react-await':
specifier: workspace:0.0.1
version: link:../../packages/react-await
'@suspensive/react-query':
- specifier: workspace:1.17.3
+ specifier: workspace:1.17.4
version: link:../../packages/react-query
'@tanstack/react-query':
specifier: ^4.29.5
diff --git a/websites/visualization/package.json b/websites/visualization/package.json
index c6e5a2ca6..8f2ee6860 100644
--- a/websites/visualization/package.json
+++ b/websites/visualization/package.json
@@ -30,9 +30,9 @@
"@emotion/react": "^11.10.8",
"@emotion/styled": "^11.10.8",
"@jsxcss/emotion": "^1.3.9",
- "@suspensive/react": "workspace:1.17.3",
+ "@suspensive/react": "workspace:1.17.4",
"@suspensive/react-await": "workspace:0.0.1",
- "@suspensive/react-query": "workspace:1.17.3",
+ "@suspensive/react-query": "workspace:1.17.4",
"@tanstack/react-query": "^4.29.5",
"@tanstack/react-query-devtools": "^4.29.5",
"@vercel/analytics": "^1.1.1",