refactor FilterInput component / enable delayed instant search

This commit is contained in:
Eduard Heimbuch
2020-11-04 12:16:35 +01:00
parent 3c32073853
commit 4661e6f6b4
2 changed files with 42 additions and 56 deletions

View File

@@ -21,66 +21,53 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
import React, { ChangeEvent, FormEvent } from "react"; import React, { FC, FormEvent, useEffect, useState } from "react";
import { WithTranslation, withTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
import { createAttributesForTesting } from "../devBuild"; import { createAttributesForTesting } from "../devBuild";
type Props = WithTranslation & { type Props = {
filter: (p: string) => void; filter: (p: string) => void;
value?: string; value?: string;
testId?: string; testId?: string;
placeholder?: string; placeholder?: string;
}; };
type State = {
value: string;
};
const FixedHeightInput = styled.input` const FixedHeightInput = styled.input`
height: 2.5rem; height: 2.5rem;
`; `;
class FilterInput extends React.Component<Props, State> { const FilterInput: FC<Props> = ({ filter, value, testId, placeholder }) => {
constructor(props: Props) { const [stateValue, setStateValue] = useState(value || "");
super(props); const [timeoutId, setTimeoutId] = useState(0);
this.state = { const [t] = useTranslation("commons");
value: this.props.value ? this.props.value : ""
}; useEffect(() => {
clearTimeout(timeoutId);
if (!stateValue) {
// no delay if filter input was deleted
filter(stateValue);
} else {
// with delay while typing
const id = setTimeout(() => filter(stateValue), 1000);
setTimeoutId(id);
} }
}, [stateValue]);
handleChange = (event: ChangeEvent<HTMLInputElement>) => { const handleSubmit = (event: FormEvent) => {
this.setState({ filter(stateValue);
value: event.target.value
});
};
handleSubmit = (event: FormEvent) => {
this.props.filter(this.state.value);
event.preventDefault(); event.preventDefault();
}; };
componentDidUpdate = ({ value: oldValue }: Props) => {
const { value: newValue } = this.props;
const { value: stateValue } = this.state;
if (oldValue !== newValue && newValue !== stateValue) {
this.setState({
value: newValue || ""
});
}
};
render() {
const { t, testId, placeholder } = this.props;
return ( return (
<form className="input-field" onSubmit={this.handleSubmit} {...createAttributesForTesting(testId)}> <form className="input-field" onSubmit={handleSubmit} {...createAttributesForTesting(testId)}>
<div className="control has-icons-left"> <div className="control has-icons-left">
<FixedHeightInput <FixedHeightInput
className="input" className="input"
type="search" type="search"
placeholder={placeholder || t("filterEntries")} placeholder={placeholder || t("filterEntries")}
value={this.state.value} value={stateValue}
onChange={this.handleChange} onChange={event => setStateValue(event.target.value)}
/> />
<span className="icon is-small is-left"> <span className="icon is-small is-left">
<i className="fas fa-search" /> <i className="fas fa-search" />
@@ -88,7 +75,6 @@ class FilterInput extends React.Component<Props, State> {
</div> </div>
</form> </form>
); );
} };
}
export default withTranslation("commons")(FilterInput); export default FilterInput;

View File

@@ -12435,10 +12435,10 @@ mini-create-react-context@^0.4.0:
"@babel/runtime" "^7.5.5" "@babel/runtime" "^7.5.5"
tiny-warning "^1.0.3" tiny-warning "^1.0.3"
mini-css-extract-plugin@^0.11.0: mini-css-extract-plugin@^0.12.0:
version "0.11.3" version "0.12.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz#15b0910a7f32e62ffde4a7430cfefbd700724ea6" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.12.0.tgz#ddeb74fd6304ca9f99c1db74acc7d5b507705454"
integrity sha512-n9BA8LonkOkW1/zn+IbLPQmovsL0wMb9yx75fMJQZf2X1Zoec9yTZtyMePcyu19wPkmFbzZZA6fLTotpFhQsOA== integrity sha512-z6PQCe9rd1XUwZ8gMaEVwwRyZlrYy8Ba1gRjFP5HcV51HkXX+XlwZ+a1iAYTjSYwgNBXoNR7mhx79mDpOn5fdw==
dependencies: dependencies:
loader-utils "^1.1.0" loader-utils "^1.1.0"
normalize-url "1.9.1" normalize-url "1.9.1"