UNPKG

1.7 kBTypeScriptView Raw
1import * as React from 'react';
2import { CurrentRenderContext } from '@react-navigation/core';
3import ServerContext, { ServerContextType } from './ServerContext';
4import type { ServerContainerRef } from './types';
5
6type Props = ServerContextType & {
7 children: React.ReactNode;
8};
9
10/**
11 * Container component for server rendering.
12 *
13 * @param props.location Location object to base the initial URL for SSR.
14 * @param props.children Child elements to render the content.
15 * @param props.ref Ref object which contains helper methods.
16 */
17export default React.forwardRef(function ServerContainer(
18 { children, location }: Props,
19 ref: React.Ref<ServerContainerRef>
20) {
21 React.useEffect(() => {
22 console.error(
23 "'ServerContainer' should only be used on the server with 'react-dom/server' for SSR."
24 );
25 }, []);
26
27 const current: { options?: object } = {};
28
29 if (ref) {
30 const value = {
31 getCurrentOptions() {
32 return current.options;
33 },
34 };
35
36 // We write to the `ref` during render instead of `React.useImperativeHandle`
37 // This is because `useImperativeHandle` will update the ref after 'commit',
38 // and there's no 'commit' phase during SSR.
39 // Mutating ref during render is unsafe in concurrent mode, but we don't care about it for SSR.
40 if (typeof ref === 'function') {
41 ref(value);
42 } else {
43 // @ts-expect-error: the TS types are incorrect and say that ref.current is readonly
44 ref.current = value;
45 }
46 }
47
48 return (
49 <ServerContext.Provider value={{ location }}>
50 <CurrentRenderContext.Provider value={current}>
51 {children}
52 </CurrentRenderContext.Provider>
53 </ServerContext.Provider>
54 );
55});