-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Better docs and correctly handle override IDs changing
- Loading branch information
Showing
2 changed files
with
72 additions
and
11 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,38 @@ | ||
import {useContext, useRef} from 'react'; | ||
import {UniqueIdFactoryContext} from './context'; | ||
|
||
export function useUniqueId(prefix = '', override?: string) { | ||
/** | ||
* Returns a unique id that remains consistent across multiple rerenders of the | ||
* same hook | ||
* @param prefix Defines a prefix for the ID. You probably want to set this to | ||
* the name of the component you're calling `useUniqueId` in. | ||
* @param overrideId Defines a fixed value to use instead of generating a unique | ||
* ID. Useful for components that allow consumers to specify a fixed ID. | ||
*/ | ||
export function useUniqueId(prefix = '', overrideId = '') { | ||
const idFactory = useContext(UniqueIdFactoryContext); | ||
|
||
// By using a ref to store the uniqueId for each incovation of the hook and | ||
// checking that it is not already populated we ensure that we don't generate | ||
// a new ID on ever rerender of a component. | ||
const uniqueIdRef = useRef<string | null>(null); | ||
|
||
if (!idFactory) { | ||
throw new Error( | ||
'No UniqueIdFactory was provided. Your application must be wrapped in an <AppProvider> component. See https://polaris.shopify.com/components/structure/app-provider for implementation instructions.', | ||
); | ||
} | ||
|
||
// Use a ref to ensure that the returned ID does not increment on every | ||
// rerendering of a component | ||
// The first time a component is rendered the ref will be empty. | ||
// In that case fill it with the next available ID | ||
// On subsequent renders we use the existing value instead of using a new id | ||
const currentComponentIdRef = useRef<string | null>(null); | ||
// If an override was specified, then use that instead of using a unique ID | ||
// Hooks can't be called conditionally so this has to go after all use* calls | ||
if (overrideId) { | ||
return overrideId; | ||
} | ||
|
||
if (!currentComponentIdRef.current) { | ||
// If an override was specified, then use that instead of incrementing the ID | ||
currentComponentIdRef.current = override || idFactory.nextId(prefix); | ||
// If a unique id has not yet been generated, then get a new one | ||
if (!uniqueIdRef.current) { | ||
uniqueIdRef.current = idFactory.nextId(prefix); | ||
} | ||
|
||
return currentComponentIdRef.current; | ||
return uniqueIdRef.current; | ||
} |
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