@chakra-ui/react#usePrevious TypeScript Examples
The following examples show how to use
@chakra-ui/react#usePrevious.
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: AsyncDualSelectWidget.tsx From ke with MIT License | 4 votes |
AsyncDualSelectWidget = (props: DualSelectWidgetProps): JSX.Element => {
const {
name,
style,
helpText,
notifier,
provider,
dataResourceUrl,
selectedTitle = 'Selected Items',
availableTitle = 'Available Items',
selectButtonTitle = 'SELECT',
unselectButtonTitle = 'UNSELECT',
getOptionLabel,
getOptionValue,
containerStore,
targetPayload,
submitChange,
copyValue,
useClipboard,
} = props
const context = containerStore.getState()
const { targetUrl, content, isRequired, widgetDescription } = useWidgetInitialization({
...props,
context,
})
const handleChange = useCallback(
(values: object[]): void => {
const inputPayload = getPayload(values, name, targetPayload)
submitChange({ url: targetUrl, payload: inputPayload })
},
[name, submitChange, targetPayload, targetUrl]
)
const [nextUrl, setNextUrl] = useState<string | null | undefined>('')
const [options, setOptions] = useState<object[]>([])
const getOptionsHandler = useCallback(
async (url: string, searchQueryValue = ''): Promise<LoadOptionsType> => {
const res = await provider
.getPage(url, [
{
filterName: 'search',
value: searchQueryValue,
},
])
.then(([data, , meta]: [object, object, Pagination]) => {
const hasMore = !!meta.nextUrl
setNextUrl(hasMore ? meta.nextUrl : '')
return {
options: data,
hasMore,
}
})
return res
},
[provider]
)
const loadOptions = useCallback(
async ({ first = false, searchQueryValue = '' }): Promise<AsyncResult<LoadOptionsType>> => {
let url = dataResourceUrl
if (!first && !!nextUrl) {
url = nextUrl
}
if (first || nextUrl) {
const res = await getOptionsHandler(url, searchQueryValue)
return res as AsyncResult<LoadOptionsType>
}
return Promise.resolve({
options: [],
hasMore: false,
})
},
[dataResourceUrl, getOptionsHandler, nextUrl]
)
const [availableSelected, setAvailableSelected] = useState<string[]>([])
const [selectedSelected, setSelectedSelected] = useState<string[]>([])
const [selectedItems, setSelectedItems] = useState<string[] | null>(null)
const selectedOptions =
(selectedItems !== null && options.filter((o) => selectedItems.includes(getOptionValue(o)))) || []
const availableOptions =
(selectedItems !== null && options.filter((o) => !selectedItems.includes(getOptionValue(o)))) || []
const isDisableSelect = availableSelected.length === 0
const isDisableUnselect = selectedSelected.length === 0
useEffect(() => {
setSelectedItems([])
loadOptions({ first: true }).then((res) => {
setOptions(res.options)
})
}, [loadOptions])
const allDeselect = useCallback(() => {
setSelectedSelected([])
setAvailableSelected([])
}, [])
const onChange = useCallback(() => {
handleChange((selectedItems !== null && options.filter((o) => selectedItems.includes(getOptionValue(o)))) || [])
allDeselect()
}, [allDeselect, getOptionValue, handleChange, options, selectedItems])
const selectButtonHandler = useCallback(() => {
setSelectedItems(availableSelected.concat((selectedItems !== null && selectedItems) || []))
}, [availableSelected, selectedItems])
const unselectButtonHandler = useCallback(() => {
setSelectedItems((selectedItems !== null && selectedItems.filter((si) => !selectedSelected.includes(si))) || [])
}, [selectedItems, selectedSelected])
const previousSelectedItems = usePrevious(selectedItems)
useEffect(() => {
if (
selectedItems !== null &&
previousSelectedItems !== null &&
selectedItems.length !== previousSelectedItems.length
) {
onChange()
}
}, [onChange, previousSelectedItems, selectedItems])
const handleCopyValue = getCopyHandler(content, copyValue)
const [searchActive, setSearchActive] = useState(false)
const [searchValue, setSearchValue] = useState<string>('')
const handleSearchToggle = useCallback(() => {
if (searchActive) {
setSearchValue('')
loadOptions({ first: true }).then((res) => {
setOptions(res.options)
})
}
setSearchActive(!searchActive)
}, [loadOptions, searchActive])
return (
<WidgetWrapper
name={name}
style={style}
helpText={helpText || 'Items'}
description={widgetDescription}
required={isRequired}
notifier={notifier}
useClipboard={useClipboard}
copyValue={handleCopyValue}
>
<Flex>
<SideContainer data-testid="ds-left-list">
<SideContainerTitle fontSize="md">
{searchActive ? (
<DebounceInput
value={searchValue}
onChange={(newValue) => {
loadOptions({ first: true, searchQueryValue: newValue }).then((res) => {
setOptions(res.options)
})
setSearchValue(newValue)
}}
style={{ paddingLeft: 5 }}
borderWidth="1px"
borderColor="gray.300"
height="20px"
debounceTimeout={700}
/>
) : (
availableTitle
)}
{searchActive ? (
<StyledCloseIcon onClick={handleSearchToggle} />
) : (
<StyledSearchIcon
style={{ ...(searchActive ? { color: 'dodgerblue' } : undefined) }}
onClick={handleSearchToggle}
/>
)}
</SideContainerTitle>
<SelectList
values={availableOptions}
selectedValues={availableSelected}
disabledValues={[]}
handleChange={(items) => {
setAvailableSelected(items)
}}
handleScrollBottom={() => {
loadOptions({}).then((res) => {
setOptions(options.concat(res.options))
})
}}
getOptionValue={getOptionValue}
getOptionLabel={getOptionLabel}
/>
</SideContainer>
<CenterContainer>
<SelectButton
isDisabled={isDisableSelect}
rightIcon={<ArrowRight />}
variant="outline"
onClick={selectButtonHandler}
>
{selectButtonTitle}
</SelectButton>
<SelectButton
isDisabled={isDisableUnselect}
leftIcon={<ArrowLeft />}
variant="outline"
onClick={unselectButtonHandler}
>
{unselectButtonTitle}
</SelectButton>
</CenterContainer>
<SideContainer data-testid="ds-right-list">
<SideContainerTitle fontSize="md">{selectedTitle}</SideContainerTitle>
<SelectList
values={selectedOptions}
selectedValues={selectedSelected}
handleChange={(items) => {
setSelectedSelected(items)
}}
getOptionValue={getOptionValue}
getOptionLabel={getOptionLabel}
/>
</SideContainer>
</Flex>
</WidgetWrapper>
)
}
Example #2
Source File: MapList.tsx From ke with MIT License | 4 votes |
MapList = <T extends MapListItem>({ containerStyle, items, clusters, initialCenter, initialZoom, initialOpenedKey, getKey, searchMarkerRadius = 2000, onViewChange, onLoad, }: MapListProps<T>): ReactElement => { const [center, setCenter] = useState(initialCenter || items[0]?.position) const [zoom, setZoom] = useState(initialZoom) const [bounds, setBounds] = useState<LatLngBounds>() const [activeKey, setActiveKey] = useState<string | undefined>(initialOpenedKey) const prevCenter = usePrevious(initialCenter) useEffect(() => { if (prevCenter !== initialCenter) { setCenter(initialCenter) } }, [initialCenter, prevCenter]) const prevValue = usePrevious(initialOpenedKey) useEffect(() => { if (prevValue !== initialOpenedKey) { setActiveKey(initialOpenedKey) } }, [initialOpenedKey, prevValue]) const handleItemClick = (item: T): void => setActiveKey(getKey(item)) const handleInfoClose = (): void => setActiveKey(undefined) const handleClusterClick = ({ bounds: clusterBounds, center: clusterCenter }: MapListCluster): void => { setZoom((prev) => { if (!clusterBounds) { return (prev || 1) + 2 } const { south, east, west, north } = clusterBounds const calcZoom = getBoundsZoomLevel( { lat: north, lng: east }, { lat: south, lng: west }, { height: 400, width: 1000 } ) return Math.max((prev || 0) + 1, calcZoom) }) setCenter(clusterCenter) } const controls = useMemo( () => ({ search: { marker: makePartial(SearchMarker, { radius: searchMarkerRadius }), }, }), [searchMarkerRadius] ) const handleZoomChange = useCallback( (z: number | undefined) => { setZoom(z) onViewChange?.({ zoom: z, bounds }) }, [bounds, onViewChange] ) const handleBoundsChange = useCallback( (b: LatLngBounds | undefined) => { setBounds(b) onViewChange?.({ zoom, bounds: b }) }, [zoom, onViewChange] ) return ( <Map containerStyle={containerStyle} center={center} onCenterChange={setCenter} zoom={zoom} onZoomChange={handleZoomChange} controls={controls} onBoundsChange={handleBoundsChange} onLoad={onLoad} > {items.map((i) => ( /* * TODO: Имеет смысл отказаться от makeUniqPosition для маркеров с одинаковыми координатами * гораздо приличнее выглядел бы маркер кластера с всплывающим блоком со списком вложенных item в * том или ином виде. Типа такого - https://yandex.ru/dev/maps/jsbox/2.1/clusterer_balloon_open/ */ <MapMarker key={getKey(i)} position={makeUniqPosition(i, items)} label={i.label} title={i.title} icon={i.icon} info={i.info} infoSize={i.infoSize} onClick={() => handleItemClick(i)} onInfoClose={handleInfoClose} isInfoOpened={activeKey !== undefined && getKey(i) === activeKey} /> ))} {clusters?.map((c) => ( <MapCluster key={`${c.center.lat}-${c.center.lng}`} center={c.center} label={c.label} onClick={() => handleClusterClick(c)} /> ))} </Map> ) }