diff --git a/packages/react-notion-x/src/styles.css b/packages/react-notion-x/src/styles.css index 965860cf3..e01a44821 100644 --- a/packages/react-notion-x/src/styles.css +++ b/packages/react-notion-x/src/styles.css @@ -1294,7 +1294,6 @@ svg.notion-page-icon { float: left; min-width: var(--notion-max-width); padding-left: 0; - transition: padding 200ms ease-out; } .notion-table-header { diff --git a/packages/react-notion-x/src/third-party/collection-view-table.tsx b/packages/react-notion-x/src/third-party/collection-view-table.tsx index 5f945aa0d..5fd3a7911 100644 --- a/packages/react-notion-x/src/third-party/collection-view-table.tsx +++ b/packages/react-notion-x/src/third-party/collection-view-table.tsx @@ -1,4 +1,4 @@ -import * as React from 'react' +import type * as React from 'react' import { useNotionContext } from '../context' import { type CollectionViewProps } from '../types' @@ -7,6 +7,7 @@ import { CollectionColumnTitle } from './collection-column-title' import { CollectionGroup } from './collection-group' import { getCollectionGroups } from './collection-utils' import { Property } from './property' +import { useClientStyle } from './react-use' const defaultBlockIds: string[] = [] @@ -72,21 +73,18 @@ function Table({ } & Omit) { const { recordMap, linkTableTitleProperties } = useNotionContext() - const tableStyle = React.useMemo( - () => ({ + const tableStyle = useClientStyle( + { width, maxWidth: width - }), - [width] + }, + { visibility: 'hidden' } ) - const tableViewStyle = React.useMemo( - () => ({ - paddingLeft: padding, - paddingRight: padding - }), - [padding] - ) + const tableViewStyle = useClientStyle({ + paddingLeft: padding, + paddingRight: padding + }) let properties = [] diff --git a/packages/react-notion-x/src/third-party/react-use.ts b/packages/react-notion-x/src/third-party/react-use.ts index 6c2581ce2..6d4af40dd 100644 --- a/packages/react-notion-x/src/third-party/react-use.ts +++ b/packages/react-notion-x/src/third-party/react-use.ts @@ -211,3 +211,20 @@ export const useLocalStorage = ( return [state, set, remove] } + +// Style mismatches between server rendering and client hydration can act +// unpredictably. Styles that depend on client state should use this hook to prevent +// a hydration mismatch by preserving the server style until the component is mounted. +// More details here: +// https://github.com/vercel/next.js/issues/17463 +export const useClientStyle = ( + clientStyle: React.CSSProperties, + serverStyle: React.CSSProperties = {} +) => { + const [isMounted, setIsMounted] = useState(false) + useEffect(() => { + setIsMounted(true) + }, []) + + return isMounted ? clientStyle : serverStyle +}