-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #212 from theKashey/suspense-hydration
Suspense hydration
- Loading branch information
Showing
14 changed files
with
134 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import React, { createContext, useCallback, useLayoutEffect, useState } from 'react'; | ||
|
||
interface ImportedState { | ||
usesHydration: boolean; | ||
pastHydration: boolean; | ||
} | ||
|
||
export const importedState = createContext<ImportedState | undefined>(undefined); | ||
|
||
export const HydrationState: React.FC<{ state: ImportedState }> = ({ state, children }) => ( | ||
<importedState.Provider value={state}>{children}</importedState.Provider> | ||
); | ||
|
||
/** | ||
* this component just creates a "the first-most" effect in the system | ||
*/ | ||
const HydrationEffect = ({ loopCallback }: { loopCallback(): void }): null => { | ||
useLayoutEffect(loopCallback, []); | ||
return null; | ||
}; | ||
|
||
/** | ||
* @see [LazyBoundary]{@link LazyBoundary} - HydrationController is required for LazyBoundary to properly work with React>16.10 | ||
* Established a control over LazyBoundary suppressing fallback during the initial hydration | ||
* @param props | ||
* @param [props.usesHydration=true] determines of Application is rendered using hydrate | ||
*/ | ||
export const ImportedController: React.FC<{ | ||
/** | ||
* determines of Application is rendered using hydrate | ||
*/ | ||
usesHydration?: boolean; | ||
}> = ({ children, usesHydration = true }) => { | ||
const [state, setState] = useState<ImportedState>({ | ||
usesHydration, | ||
pastHydration: false, | ||
}); | ||
|
||
const onFirstHydration = useCallback(() => setState(oldState => ({ ...oldState, pastHydration: true })), []); | ||
return ( | ||
<> | ||
<HydrationEffect loopCallback={onFirstHydration} /> | ||
<HydrationState state={state}>{children}</HydrationState> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,26 @@ | ||
import * as React from 'react'; | ||
import { isBackend } from '../utils/detectBackend'; | ||
import { useIsClientPhase } from '../utils/useClientPhase'; | ||
|
||
const LazyBoundary: React.FC<{ | ||
const LazyServerBoundary: React.FC<{ | ||
fallback: NonNullable<React.ReactNode> | null; | ||
}> = ({ children }) => <React.Fragment>{children}</React.Fragment>; | ||
|
||
const LazyClientBoundary: React.FC<{ | ||
fallback: NonNullable<React.ReactNode> | null; | ||
}> = ({ children, fallback }) => ( | ||
<React.Suspense | ||
// we keep fallback null during hydration as it is expected behavior for "ssr-ed" Suspense blocks - they should not "fallback" | ||
// see https://github.com/sebmarkbage/react/blob/185700696ebbe737c99bd6c4b678d5f2a923bd29/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js#L668-L682 | ||
fallback={useIsClientPhase() ? fallback : (undefined as any)} | ||
> | ||
{children} | ||
</React.Suspense> | ||
); | ||
|
||
/** | ||
* React.Suspense "as-is" replacement | ||
* React.Suspense "as-is" replacement. Automatically "removed" during SSR and "patched" to work accordingly on the clientside | ||
* | ||
* @see {@link HydrationController} has to wrap entire application in order to provide required information | ||
*/ | ||
const Boundary = isBackend ? LazyBoundary : React.Suspense; | ||
|
||
export default Boundary; | ||
export const LazyBoundary = isBackend ? LazyServerBoundary : LazyClientBoundary; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useContext } from 'react'; | ||
import { importedState } from '../ui/ImportedController'; | ||
|
||
/** | ||
* returns "true" if currently is a "client" phase and all features should be active | ||
* @see {@link HydrationController} | ||
*/ | ||
export const useIsClientPhase = (): boolean => { | ||
const value = useContext(importedState); | ||
if (!value) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
// tslint:disable-next-line:no-console | ||
console.warn('react-imported-component: please wrap your entire application with ImportedController'); | ||
} | ||
return true; | ||
} | ||
return value.pastHydration; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters