diff --git a/apps/ssr-tests-v9/package.json b/apps/ssr-tests-v9/package.json index 27896f18d76f2..bf55eab6a4bae 100644 --- a/apps/ssr-tests-v9/package.json +++ b/apps/ssr-tests-v9/package.json @@ -18,7 +18,8 @@ "test-ssr": "test-ssr \"./src/stories/**/*.stories.tsx\"" }, "dependencies": { - "@fluentui/react-components": "*" + "@fluentui/react-components": "*", + "@fluentui/react-utilities": "*" }, "devDependencies": { "@fluentui/eslint-plugin": "*", diff --git a/apps/ssr-tests-v9/src/stories/Utilitites/index.stories.tsx b/apps/ssr-tests-v9/src/stories/Utilitites/index.stories.tsx new file mode 100644 index 0000000000000..d06c147c86884 --- /dev/null +++ b/apps/ssr-tests-v9/src/stories/Utilitites/index.stories.tsx @@ -0,0 +1,5 @@ +export { Default } from './useAnimationFrame.stories'; + +export default { + title: 'Utilities/useAnimationFrame', +}; diff --git a/apps/ssr-tests-v9/src/stories/Utilitites/useAnimationFrame.stories.tsx b/apps/ssr-tests-v9/src/stories/Utilitites/useAnimationFrame.stories.tsx new file mode 100644 index 0000000000000..aba7f94b251a8 --- /dev/null +++ b/apps/ssr-tests-v9/src/stories/Utilitites/useAnimationFrame.stories.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { useAnimationFrame } from '@fluentui/react-utilities'; + +export const Default = () => { + const [setAnimationFrame, clearAnimationFrame] = useAnimationFrame(); + const [visible, setVisible] = React.useState(false); + + React.useEffect(() => { + setAnimationFrame(() => setVisible(true)); + + return () => clearAnimationFrame(); + }, [setAnimationFrame]); + + return visible ?
Test the renderization
: null; +}; diff --git a/change/@fluentui-react-utilities-b4af8469-27c7-4b29-a6a9-13ef542e6779.json b/change/@fluentui-react-utilities-b4af8469-27c7-4b29-a6a9-13ef542e6779.json new file mode 100644 index 0000000000000..0b0617f983224 --- /dev/null +++ b/change/@fluentui-react-utilities-b4af8469-27c7-4b29-a6a9-13ef542e6779.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: use timeout instead of requestAnimationFrame for ssr", + "packageName": "@fluentui/react-utilities", + "email": "marcosvmmoura@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-utilities/src/hooks/useAnimationFrame.ts b/packages/react-components/react-utilities/src/hooks/useAnimationFrame.ts index f2453bd545a4d..a95e862aad739 100644 --- a/packages/react-components/react-utilities/src/hooks/useAnimationFrame.ts +++ b/packages/react-components/react-utilities/src/hooks/useAnimationFrame.ts @@ -1,5 +1,12 @@ +import { canUseDOM } from '../ssr/canUseDOM'; import { useBrowserTimer } from './useBrowserTimer'; +const setAnimationFrameNoop = (callback: FrameRequestCallback) => { + callback(0); + return 0; +}; +const cancelAnimationFrameNoop = (handle: number) => handle; + /** * @internal * Helper to manage a browser requestAnimationFrame. @@ -9,6 +16,11 @@ import { useBrowserTimer } from './useBrowserTimer'; * @returns A pair of [requestAnimationFrame, cancelAnimationFrame] that are stable between renders. */ export function useAnimationFrame() { + const isDOM = canUseDOM(); + // TODO: figure it out a way to not call global.requestAnimationFrame and instead infer window from some context - return useBrowserTimer(requestAnimationFrame, cancelAnimationFrame); + const setAnimationFrame = isDOM ? requestAnimationFrame : setAnimationFrameNoop; + const clearAnimationFrame = isDOM ? cancelAnimationFrame : cancelAnimationFrameNoop; + + return useBrowserTimer(setAnimationFrame, clearAnimationFrame); }