From a9a30db7ec9505450da696ccf660edc20fe2ac0b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Kuty=C5=82a?= Date: Tue, 18 Oct 2022 17:27:07 +0200 Subject: [PATCH] 19311: changed search component to a functional style MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła --- .../search-input/search-input.test.tsx | 22 +-- src/components/search-input/search-input.tsx | 135 +++++++++--------- 2 files changed, 67 insertions(+), 90 deletions(-) diff --git a/src/components/search-input/search-input.test.tsx b/src/components/search-input/search-input.test.tsx index c1bd79ab..0cb56ea1 100644 --- a/src/components/search-input/search-input.test.tsx +++ b/src/components/search-input/search-input.test.tsx @@ -98,30 +98,10 @@ describe("", () => { describe("on input target change", () => { it("clears the input value on selfClearProp change", () => { const searchInput = mount(); - // initial no clear call - jest.runTimersToTime(0); searchInput.setProps({ selfClearProp: '111' }); - expect(onSearch).not.toBeCalledWith(""); - expect(onSearch).toHaveBeenCalledTimes(0); - - // second call trigger input clear - searchInput.setProps({ selfClearProp: 'aaa111' }); - jest.runTimersToTime(0); - expect(onSearch).toBeCalledWith(""); - expect(onSearch).toHaveBeenCalledTimes(1); - - // third call trigger not input clear beacuse of the same selfClearProp value - searchInput.setProps({ selfClearProp: 'aaa111', value: '321' }); - jest.runTimersToTime(0); + jest.runTimersToTime(1000); expect(onSearch).toBeCalledWith(""); expect(onSearch).toHaveBeenCalledTimes(1); - expect(searchInput.props().value).toBe('321'); - - // third call trigger input clear beacuse of different selfClearProp value - searchInput.setProps({ selfClearProp: 'aaa222' }); - jest.runTimersToTime(0); - expect(onSearch).toBeCalledWith(""); - expect(onSearch).toHaveBeenCalledTimes(2); }); }); }); diff --git a/src/components/search-input/search-input.tsx b/src/components/search-input/search-input.tsx index 2835f156..f7007b69 100644 --- a/src/components/search-input/search-input.tsx +++ b/src/components/search-input/search-input.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0 -import React from 'react'; +import React, {useState, useEffect} from 'react'; import { IconButton, StyleRulesCallback, withStyles, WithStyles, FormControl, InputLabel, Input, InputAdornment, Tooltip } from '@material-ui/core'; import SearchIcon from '@material-ui/icons/Search'; @@ -45,84 +45,81 @@ interface SearchInputActionProps { type SearchInputProps = SearchInputDataProps & SearchInputActionProps & WithStyles; -interface SearchInputState { - value: string; - label: string; -} +// interface SearchInputState { +// value: string; +// label: string; +// } -let selfClearPropState = ''; +// let selfClearPropState = ''; export const DEFAULT_SEARCH_DEBOUNCE = 1000; -export const SearchInput = withStyles(styles)( - class extends React.Component { - state: SearchInputState = { - value: "", - label: "" - }; +const SearchInputComponent = (props: SearchInputProps) => { + const [timeout, setTimeout] = useState(1); + const [value, setValue] = useState(""); + const [label, setLabel] = useState("Search"); + const [selfClearProp, setSelfClearProp] = useState(""); - timeout: number; - - render() { - return
- - {this.state.label} - - - - - - - - } /> - -
; + useEffect(() => { + if (props.value) { + setValue(props.value); } - - componentDidMount() { - this.setState({ - value: this.props.value, - label: this.props.label || 'Search' - }); + if (props.label) { + setLabel(props.label); } - componentWillReceiveProps(nextProps: SearchInputProps) { - if (nextProps.value !== this.props.value) { - this.setState({ value: nextProps.value }); - } - if (this.state.value !== '' && nextProps.selfClearProp && nextProps.selfClearProp !== selfClearPropState) { - if (selfClearPropState !== '') { - this.props.onSearch(''); - } - selfClearPropState = nextProps.selfClearProp; - } - } + return () => { + setValue(""); + clearTimeout(timeout); + }; + }, [props.value, props.label]); // eslint-disable-line react-hooks/exhaustive-deps - componentWillUnmount() { - clearTimeout(this.timeout); + useEffect(() => { + if (selfClearProp !== props.selfClearProp) { + setValue(""); + setSelfClearProp(props.selfClearProp); + handleChange({ target: { value: "" } } as any); } + }, [props.selfClearProp]); // eslint-disable-line react-hooks/exhaustive-deps - handleSubmit = (event: React.FormEvent) => { - event.preventDefault(); - clearTimeout(this.timeout); - this.props.onSearch(this.state.value); - } + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + clearTimeout(timeout); + props.onSearch(value); + }; + + const handleChange = (event: React.ChangeEvent) => { + const { target: { value: eventValue } } = event; + clearTimeout(timeout); + setValue(eventValue); + setTimeout(window.setTimeout( + () => { + props.onSearch(eventValue); + }, + props.debounce || DEFAULT_SEARCH_DEBOUNCE + )); + }; - handleChange = (event: React.ChangeEvent) => { - clearTimeout(this.timeout); - this.setState({ value: event.target.value }); - this.timeout = window.setTimeout( - () => this.props.onSearch(this.state.value), - this.props.debounce || DEFAULT_SEARCH_DEBOUNCE - ); + return
+ + {label} + + + + + + + + } /> + +
; +} - } - } -); +export const SearchInput = withStyles(styles)(SearchInputComponent); \ No newline at end of file -- 2.30.2