hooks#useIsMounted TypeScript Examples
The following examples show how to use
hooks#useIsMounted.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From exevo-pan with The Unlicense | 5 votes |
AuctionsProvider = ({
initialPage,
initialPageData,
children,
}: AuctionsProviderProps) => {
const [state, dispatch] = useReducer(AuctionsReducer, {
loading: DEFAULT_STATE.loading,
nickname: DEFAULT_STATE.nickname,
page: initialPage,
pageData: initialPageData,
})
const {
nickname,
pageData: { pageIndex },
} = state
const previousNickname = useRef(DEFAULT_STATE.nickname)
const fetchData = useCallback(
async (newPageIndex: number, newNickname: string) => {
dispatch({ type: 'SET_LOADING' })
const nicknameChanged = previousNickname.current !== newNickname
const data = await AuctionsClient.fetchAuctionPage({
paginationOptions: {
pageIndex: nicknameChanged ? 0 : newPageIndex,
pageSize: PAGE_SIZE,
},
filterOptions: {
...DEFAULT_FILTER_OPTIONS,
nicknameFilter: newNickname,
},
endpoint: endpoints.CURRENT_AUCTIONS,
})
previousNickname.current = newNickname
dispatch({ type: 'STORE_DATA', data })
},
[],
)
const isMounted = useIsMounted()
useEffect(() => {
if (isMounted) {
fetchData(pageIndex, nickname)
}
}, [pageIndex, nickname, fetchData])
const handlePaginatorFetch = useCallback((newPageIndex: number) => {
dispatch({ type: 'SET_PAGE_INDEX', value: newPageIndex - 1 })
}, [])
const handleNicknameFetch = useCallback((newNickname: string) => {
dispatch({ type: 'SET_NICKNAME', value: newNickname })
}, [])
return (
<AuctionsContext.Provider
value={{ ...state, handlePaginatorFetch, handleNicknameFetch }}
>
{children}
</AuctionsContext.Provider>
)
}
Example #2
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
Drawer = ({
isOpen,
onClose,
children,
className,
...props
}: DrawerProps) => {
const initialDrag = useRef<number | null>(null)
const [drawerOffset, setDrawerOffset] = useState<number>(0)
const [shouldBeRendered, setShouldBeRendered] = useState<boolean>(isOpen)
useLockBody(isOpen)
const { elementToFocusRef, onKeyDown } = useEscToClose({
open: isOpen,
onClose,
})
const { binders, isMousePressed, position } = useDrag()
useEffect(() => {
if (!initialDrag.current && isMousePressed) {
initialDrag.current = position.x
} else if (initialDrag.current && !isMousePressed) {
initialDrag.current = null
onClose()
setTimeout(() => setDrawerOffset(0), 200)
}
}, [isMousePressed, onClose, position.x])
useEffect(() => {
if (initialDrag.current) {
const offset = position.x - initialDrag.current
if (offset < 0) {
setDrawerOffset(position.x - initialDrag.current)
} else {
setDrawerOffset(0)
}
}
}, [position.x, initialDrag])
const isMounted = useIsMounted()
useEffect(() => {
if (!isOpen) {
setTimeout(() => setShouldBeRendered(false), 200)
} else {
setShouldBeRendered(true)
}
}, [isOpen])
return isMounted && shouldBeRendered
? createPortal(
<FocusLock>
<div
tabIndex={0}
aria-hidden={!isOpen}
aria-modal="true"
role="dialog"
ref={elementToFocusRef}
onKeyDown={onKeyDown}
className={clsx(
'animate-slideIn z-75 bg-surface fixed top-0 left-0 flex h-screen w-[90vw] max-w-[600px] flex-col shadow-lg outline-none',
!isOpen && 'invisible opacity-0',
className,
)}
style={{
marginLeft: `${drawerOffset}px`,
transform: `translateX(${isOpen ? '0' : '-100%'})`,
transition: '0.2s ease-out',
transitionProperty: 'opacity, transform, visibility',
}}
{...props}
>
{children}
</div>
<div
className={clsx(
'z-74 animate-fadeIn bg-backdrop fixed top-0 left-0 h-screen w-screen transition-all',
!isOpen && 'pointer-events-none opacity-0',
)}
style={{ cursor: isMousePressed ? 'grabbing' : 'unset' }}
aria-hidden={!isOpen}
{...binders}
/>
</FocusLock>,
document.body,
)
: null
}
Example #3
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
RangeSliderInput = ({
className,
min,
max,
onChange,
value: propValue = [min, max],
...props
}: RangeSliderInputProps) => {
const {
translations: { common },
} = useTranslations()
const [cursorAValue, setCursorAValue] = useState(propValue[0])
const [cursorBValue, setCursorBValue] = useState(propValue[1])
const [currentCursor, setCurrentCursor] = useState<'A' | 'B'>('A')
const [currentTrackCursor, setCurrentTrackCursor] = useState<
'A' | 'B' | null
>(null)
const isMounted = useIsMounted()
const track = useDrag()
const trackRef = useRef<HTMLDivElement>(null)
const trackWidth: number = trackRef.current?.offsetWidth ?? 1
const positionToValue = useCallback(
(position: number): number =>
Math.round((max - min) * (position / trackWidth) + min),
[min, max, trackWidth],
)
useEffect(() => {
if (track.isMousePressed) {
const { x } = track.position
const trackValue = clampValue(positionToValue(x), [min, max])
const newCurrentCursor =
Math.abs(trackValue - cursorAValue) <=
Math.abs(trackValue - cursorBValue)
? 'A'
: 'B'
setCurrentCursor(newCurrentCursor)
if (currentTrackCursor) {
const updateCurrentCursorValue = {
A: setCursorAValue,
B: setCursorBValue,
}[currentTrackCursor]
updateCurrentCursorValue(trackValue)
} else {
const updateCurrentCursorValue = {
A: setCursorAValue,
B: setCursorBValue,
}[newCurrentCursor]
setCurrentTrackCursor(newCurrentCursor)
updateCurrentCursorValue(trackValue)
}
} else {
setCurrentTrackCursor(null)
}
}, [
track.position.x,
track.isMousePressed,
cursorAValue,
cursorBValue,
max,
min,
positionToValue,
currentTrackCursor,
])
const handleKeyPress = (event: React.KeyboardEvent) => {
const { ctrlKey, shiftKey } = event
const increment = 1 * (+!ctrlKey || 10) * (+!shiftKey || 100)
const action = {
ArrowUp: (value: number) => value + increment,
ArrowRight: (value: number) => value + increment,
ArrowDown: (value: number) => value - increment,
ArrowLeft: (value: number) => value - increment,
}[event.code]
if (!action) return
event.nativeEvent.preventDefault()
if (currentCursor === 'A') {
setCursorAValue((prev) => clampValue(action(prev), [min, max]))
} else {
setCursorBValue((prev) => clampValue(action(prev), [min, max]))
}
}
const dispatchOnChange = useMemo(
() =>
debounce((aValue, bValue) => {
onChange?.([aValue, bValue].sort((a, b) => a - b) as [number, number])
}, 500),
[onChange],
)
useEffect(() => {
if (isMounted) dispatchOnChange(cursorAValue, cursorBValue)
}, [dispatchOnChange, cursorAValue, cursorBValue])
useLayoutEffect(() => {
const [newMin, newMax] = propValue
setCursorAValue(newMin)
setCursorBValue(newMax)
}, [propValue])
const trackFillLeft =
normalize(Math.min(cursorAValue, cursorBValue), [min, max]) * 100
const trackFillRight =
normalize(Math.max(cursorAValue, cursorBValue), [min, max]) * 100
const cursorAPosition =
normalize(clampValue(cursorAValue, [min, max]), [min, max]) * 100
const cursorBPosition =
normalize(clampValue(cursorBValue, [min, max]), [min, max]) * 100
return (
<div
className={clsx('flex w-[270px] items-center gap-3', className)}
{...props}
>
<ValueDisplay>
{clampValue(Math.min(cursorAValue, cursorBValue), [min, max])}
</ValueDisplay>
<div className="w-full">
<TrackFill
ref={trackRef}
tabIndex={0}
onKeyDown={(event) => handleKeyPress(event)}
isMousePressed={track.isMousePressed}
{...track.binders}
>
<Cursor
role="slider"
aria-label={common.ChangeValueLabel}
aria-valuenow={cursorAValue}
aria-valuemax={max}
aria-valuemin={min}
style={{ left: `${cursorAPosition}%` }}
/>
<Cursor
role="slider"
aria-label={common.ChangeValueLabel}
aria-valuenow={cursorBValue}
aria-valuemax={max}
aria-valuemin={min}
style={{ left: `${cursorBPosition}%` }}
/>
<div
className="bg-primary absolute top-0 h-full opacity-70"
style={{
left: `${trackFillLeft}%`,
width: `${trackFillRight - trackFillLeft}%`,
}}
/>
</TrackFill>
</div>
<ValueDisplay>
{clampValue(Math.max(cursorAValue, cursorBValue), [min, max])}
</ValueDisplay>
</div>
)
}
Example #4
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
SliderInput = ({
className,
style,
min,
max,
onChange,
value: propValue = min,
...props
}: SliderInputProps) => {
const {
translations: { common },
} = useTranslations()
const [value, setValue] = useState<number>(propValue)
const [sliderInputValue, setSliderInputValue] = useState<string>(
propValue.toString(),
)
const inputRef = useRef<HTMLInputElement>(null)
const trackRef = useRef<HTMLDivElement>(null)
const trackWidth: number = trackRef.current?.offsetWidth ?? 1
const positionToValue = useCallback(
(position: number): number =>
Math.round((max - min) * (position / trackWidth) + min),
[min, max, trackWidth],
)
const valueToTrackPercentage = (currentValue: number): string =>
`${clampValue(normalize(currentValue, [min, max]), [0, 1]) * 100}%`
const isMounted = useIsMounted()
const { binders, isMousePressed, position } = useDrag()
const cursorPosition = clampValue(position.x, [0, trackWidth])
const intSliderInputValue = strToInt(sliderInputValue)
const isValid =
sliderInputValue === '-' ||
sliderInputValue === clampValue(intSliderInputValue, [min, max]).toString()
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const matches = event.target.value.match(/^-?[0-9]*/) ?? ['']
const sanitized = matches[0]
const newValue = strToInt(sanitized)
if (Number.isNaN(newValue) || newValue < min) {
setSliderInputValue(sanitized)
} else {
const boundedValue = clampValue(newValue, [min, max])
setValue(boundedValue)
setSliderInputValue(boundedValue.toString())
}
}
const handleInputBlur = (event: React.FocusEvent) => {
if (!isValid || (event.target as HTMLInputElement).value === '-') {
setSliderInputValue(min.toString())
setValue(min)
}
}
const handleInputKeyPress = (event: React.KeyboardEvent) => {
const { ctrlKey, shiftKey } = event
const increment = 1 * (+!ctrlKey || 10) * (+!shiftKey || 100)
const action = {
ArrowUp: (prev: number) => prev + increment,
ArrowDown: (prev: number) => prev - increment,
}[event.code]
if (!action) return
event.nativeEvent.preventDefault()
setValue((prev) => clampValue(action(prev), [min, max]))
}
const handleTrackKeyPress = (event: React.KeyboardEvent) => {
const { ctrlKey, shiftKey } = event
const increment = 1 * (+!ctrlKey || 10) * (+!shiftKey || 100)
const action = {
ArrowUp: (prev: number) => prev + increment,
ArrowRight: (prev: number) => prev + increment,
ArrowDown: (prev: number) => prev - increment,
ArrowLeft: (prev: number) => prev - increment,
}[event.code]
if (!action) return
event.nativeEvent.preventDefault()
setValue((prev) => clampValue(action(prev), [min, max]))
}
useEffect(() => {
if (isMousePressed) {
const newValue = positionToValue(cursorPosition)
setValue(newValue)
}
}, [isMousePressed, positionToValue, cursorPosition])
const dispatchSyntheticEvent = useMemo(
() =>
debounce(() => {
const event = new Event('input', { bubbles: true })
inputRef.current?.dispatchEvent(event)
}, 250),
[],
)
useEffect(() => {
setSliderInputValue(value.toString())
if (isMounted) dispatchSyntheticEvent()
}, [value, dispatchSyntheticEvent])
useLayoutEffect(() => {
setValue(propValue)
}, [propValue])
return (
<div
className={clsx('flex w-[270px] items-center gap-3 pl-2', className)}
style={style}
>
<div style={{ width: '100%' }}>
<TrackFill
ref={trackRef}
isMousePressed={isMousePressed}
tabIndex={0}
onKeyDown={handleTrackKeyPress}
{...binders}
>
<Cursor
role="slider"
aria-label={common.ChangeValueLabel}
aria-valuenow={value}
aria-valuemax={max}
aria-valuemin={min}
style={{ left: valueToTrackPercentage(value) }}
/>
<div
className="bg-primary after:bg-primary pointer-events-none absolute top-0 left-0 h-full after:pointer-events-none after:absolute after:right-full after:top-0 after:h-full after:w-[7px]"
style={{ width: valueToTrackPercentage(value) }}
/>
</TrackFill>
</div>
<input
aria-label={props['aria-label']}
aria-labelledby={props['aria-labelledby']}
aria-invalid={!isValid}
value={sliderInputValue}
onChange={handleInputChange}
onBlur={handleInputBlur}
onKeyDown={handleInputKeyPress}
className={clsx(
'text-tsm selection:bg-primary selection:text-onPrimary w-10 shrink-0 rounded-lg border-none py-[7px] text-center outline-none transition-colors',
isValid
? 'bg-primaryVariant text-onSurface'
: 'bg-red text-onPrimary selection',
)}
/>
<input
hidden
aria-invalid={!isValid}
value={value}
onInput={(event) =>
onChange?.(event as React.ChangeEvent<HTMLInputElement>)
}
ref={inputRef}
{...props}
/>
</div>
)
}
Example #5
Source File: index.tsx From exevo-pan with The Unlicense | 4 votes |
AuctionsProvider = ({
endpoint,
highlightedAuctions,
initialPage,
initialPageData,
defaultSortingMode,
defaultDescendingOrder,
children,
}: AuctionsProviderProps) => {
const {
translations: { common },
} = useTranslations()
const {
current: { isCurrentlyDefaultValues, getUrlValues, setUrlValues },
} = useRef(
urlParametersState(buildSchema(defaultSortingMode, defaultDescendingOrder)),
)
const initialUrlState = useRef(getUrlValues())
const [state, dispatch] = useReducer(AuctionsReducer, {
loading: false,
page: initialPage,
pageData: {
...initialPageData,
pageIndex: initialUrlState.current.currentPage - 1,
},
sortingMode: initialUrlState.current.orderBy,
descendingOrder: initialUrlState.current.descending,
shouldDisplayHighlightedAuctions:
DEFAULT_STATE.shouldDisplayHighlightedAuctions,
})
const {
pageData: { pageIndex },
sortingMode,
descendingOrder,
} = state
const { filterState, activeFilterCount } = useFilters()
const lastFilterState = useRef(filterState)
const fetchData = useCallback(
async (
newPageIndex: number,
newSortingMode: number,
newDescendingOrder: boolean,
filterOptions: FilterOptions,
newFilterCount: number,
) => {
dispatch({ type: 'SET_LOADING' })
lastFilterState.current = filterOptions
const paginationOptions = {
pageIndex: newPageIndex,
pageSize: PAGE_SIZE,
}
const sortOptions = {
sortingMode: newSortingMode,
descendingOrder: newDescendingOrder,
}
const data = await AuctionsClient.fetchAuctionPage({
paginationOptions,
sortOptions,
filterOptions,
endpoint,
})
const isDefaultGridState =
newPageIndex === 0 &&
newSortingMode === defaultSortingMode &&
newDescendingOrder === defaultDescendingOrder
const noFilterApplied = newFilterCount === 0
dispatch({
type: 'STORE_DATA',
data,
shouldDisplayHighlightedAuctions: isDefaultGridState && noFilterApplied,
})
},
[endpoint],
)
const isMounted = useIsMounted()
useEffect(() => {
if (isMounted) {
const filterChanged = !dequal(filterState, lastFilterState.current)
fetchData(
filterChanged ? 0 : pageIndex,
sortingMode,
descendingOrder,
filterState,
activeFilterCount,
)
}
}, [
pageIndex,
sortingMode,
descendingOrder,
filterState,
activeFilterCount,
fetchData,
])
/* Detecting and fetching new data if there are url parameters */
useEffect(() => {
if (!isMounted) {
if (!isCurrentlyDefaultValues() || activeFilterCount > 0) {
const { currentPage, orderBy, descending } = initialUrlState.current
fetchData(
currentPage - 1,
orderBy,
descending,
filterState,
activeFilterCount,
)
}
}
}, [])
useEffect(
() =>
setUrlValues({
currentPage: pageIndex + 1,
descending: descendingOrder,
orderBy: sortingMode,
}),
[pageIndex, descendingOrder, sortingMode],
)
const handlePaginatorFetch = useCallback((newPageIndex: number) => {
dispatch({ type: 'SET_PAGE_INDEX', value: newPageIndex - 1 })
}, [])
return (
<AuctionsContext.Provider
value={{
...state,
highlightedAuctions,
handlePaginatorFetch,
dispatch,
}}
>
{state.loading && <LoadingAlert>{common.LoadingState}</LoadingAlert>}
{children}
</AuctionsContext.Provider>
)
}