add useUpdateEffect and useFirstMountState | add endAdornment to search input
This commit is contained in:
parent
4b4cd887ec
commit
feffa53487
|
@ -1,7 +1,8 @@
|
||||||
import React from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import { useQueryParams, StringParam, withDefault } from 'use-query-params';
|
import { useQueryParams, StringParam, withDefault } from 'use-query-params';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import useUpdateEffect from '@libs/useUpdateEffect';
|
||||||
import { TWHELP, NAME } from '@config/app';
|
import { TWHELP, NAME } from '@config/app';
|
||||||
import * as NAMESPACES from '@config/namespaces';
|
import * as NAMESPACES from '@config/namespaces';
|
||||||
|
|
||||||
|
@ -15,18 +16,24 @@ import {
|
||||||
Button,
|
Button,
|
||||||
Hidden,
|
Hidden,
|
||||||
Link,
|
Link,
|
||||||
|
IconButton,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import { Search as SearchIcon } from '@material-ui/icons';
|
import { Search as SearchIcon, Close as CloseIcon } from '@material-ui/icons';
|
||||||
import VersionSelector from '@common/VersionSelector/VersionSelector';
|
import VersionSelector from '@common/VersionSelector/VersionSelector';
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
|
const input = useRef<HTMLInputElement | null>(null);
|
||||||
const [query, setQuery] = useQueryParams({
|
const [query, setQuery] = useQueryParams({
|
||||||
q: withDefault(StringParam, ''),
|
q: withDefault(StringParam, ''),
|
||||||
});
|
});
|
||||||
|
const [q, setQ] = useState(query.q);
|
||||||
const debouncedSetQuery = useDebouncedCallback(
|
const debouncedSetQuery = useDebouncedCallback(
|
||||||
value => setQuery({ q: value }),
|
value => setQuery({ q: value }),
|
||||||
1000
|
1000
|
||||||
);
|
);
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
debouncedSetQuery.callback(q);
|
||||||
|
}, [q]);
|
||||||
const { t } = useTranslation(NAMESPACES.INDEX_PAGE);
|
const { t } = useTranslation(NAMESPACES.INDEX_PAGE);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
|
@ -39,18 +46,37 @@ export default function Header() {
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
placeholder={t<string>('header.search')}
|
placeholder={t<string>('header.search')}
|
||||||
defaultValue={query.q}
|
value={q}
|
||||||
|
inputRef={input}
|
||||||
size="small"
|
size="small"
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
debouncedSetQuery.callback(e.target.value);
|
setQ(e.target.value);
|
||||||
}}
|
}}
|
||||||
style={{ backgroundColor: 'rgba(0, 0, 0, 0.1)' }}
|
style={{ backgroundColor: 'rgba(0, 0, 0, 0.1)' }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: (
|
startAdornment: (
|
||||||
<InputAdornment position="start">
|
<InputAdornment
|
||||||
|
position="start"
|
||||||
|
onClick={() => {
|
||||||
|
if (input.current) {
|
||||||
|
input.current.focus();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
),
|
),
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
disabled={q === ''}
|
||||||
|
onClick={() => setQ('')}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
13
src/libs/useFirstMountState.ts
Normal file
13
src/libs/useFirstMountState.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { useRef } from 'react';
|
||||||
|
|
||||||
|
export default function useFirstMountState(): boolean {
|
||||||
|
const isFirst = useRef(true);
|
||||||
|
|
||||||
|
if (isFirst.current) {
|
||||||
|
isFirst.current = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFirst.current;
|
||||||
|
}
|
14
src/libs/useUpdateEffect.ts
Normal file
14
src/libs/useUpdateEffect.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import useFirstMountState from './useFirstMountState';
|
||||||
|
|
||||||
|
const useUpdateEffect: typeof useEffect = (effect, deps) => {
|
||||||
|
const isFirstMount = useFirstMountState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isFirstMount) {
|
||||||
|
return effect();
|
||||||
|
}
|
||||||
|
}, deps);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useUpdateEffect;
|
Reference in New Issue
Block a user