Rewrite mock choice provider to hooks
This commit is contained in:
parent
ba5dac7405
commit
d58b1046ff
1 changed files with 88 additions and 80 deletions
|
@ -1,91 +1,99 @@
|
|||
import React from "react";
|
||||
|
||||
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent";
|
||||
import { FetchMoreProps } from "@saleor/types";
|
||||
|
||||
interface ChoiceProviderProps {
|
||||
children: (props: {
|
||||
choices: SingleAutocompleteChoiceType[];
|
||||
hasMore: boolean;
|
||||
loading: boolean;
|
||||
fetchChoices: (value: string) => void;
|
||||
fetchMore: () => void;
|
||||
}) => React.ReactElement<any>;
|
||||
children: (
|
||||
props: FetchMoreProps & {
|
||||
choices: SingleAutocompleteChoiceType[];
|
||||
fetchChoices: (value: string) => void;
|
||||
}
|
||||
) => React.ReactElement;
|
||||
choices: SingleAutocompleteChoiceType[];
|
||||
}
|
||||
interface ChoiceProviderState {
|
||||
choices: SingleAutocompleteChoiceType[];
|
||||
filteredChoices: SingleAutocompleteChoiceType[];
|
||||
first: number;
|
||||
loading: boolean;
|
||||
timeout: any;
|
||||
}
|
||||
|
||||
const step = 5;
|
||||
const loadingTime = 400;
|
||||
|
||||
export class ChoiceProvider extends React.Component<
|
||||
ChoiceProviderProps,
|
||||
ChoiceProviderState
|
||||
> {
|
||||
state = {
|
||||
choices: [],
|
||||
filteredChoices: [],
|
||||
first: step,
|
||||
loading: false,
|
||||
timeout: null
|
||||
};
|
||||
|
||||
handleChange = (inputValue: string) => {
|
||||
if (!!this.state.timeout) {
|
||||
clearTimeout(this.state.timeout);
|
||||
}
|
||||
const timeout = setTimeout(() => this.fetchChoices(inputValue), 500);
|
||||
this.setState({
|
||||
loading: true,
|
||||
timeout
|
||||
});
|
||||
};
|
||||
|
||||
handleFetchMore = () => {
|
||||
if (!!this.state.timeout) {
|
||||
clearTimeout(this.state.timeout);
|
||||
}
|
||||
const timeout = setTimeout(this.fetchMore, 500);
|
||||
this.setState({
|
||||
loading: true,
|
||||
timeout
|
||||
});
|
||||
};
|
||||
|
||||
fetchMore = () =>
|
||||
this.setState(prevState => ({
|
||||
filteredChoices: prevState.choices.slice(0, prevState.first + step),
|
||||
first: prevState.first + step,
|
||||
loading: false,
|
||||
timeout: null
|
||||
}));
|
||||
|
||||
fetchChoices = (inputValue: string) => {
|
||||
const choices = this.props.choices.filter(
|
||||
suggestion =>
|
||||
!inputValue ||
|
||||
suggestion.label.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1
|
||||
);
|
||||
this.setState({
|
||||
choices,
|
||||
filteredChoices: choices.slice(0, step),
|
||||
first: step,
|
||||
loading: false,
|
||||
timeout: null
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return this.props.children({
|
||||
choices: this.state.filteredChoices,
|
||||
fetchChoices: this.handleChange,
|
||||
fetchMore: this.handleFetchMore,
|
||||
hasMore: this.state.choices.length > this.state.filteredChoices.length,
|
||||
loading: this.state.loading
|
||||
});
|
||||
}
|
||||
export interface UseMockChoiceProviderOpts extends FetchMoreProps {
|
||||
fetchChoices: (value: string) => void;
|
||||
}
|
||||
export type UseMockChoiceProvider = [
|
||||
SingleAutocompleteChoiceType[],
|
||||
UseMockChoiceProviderOpts
|
||||
];
|
||||
export function useMockChoiceProvider(
|
||||
choices: SingleAutocompleteChoiceType[]
|
||||
): UseMockChoiceProvider {
|
||||
const [filteredChoices, setFilteredChoices] = React.useState(
|
||||
choices.slice(0, step)
|
||||
);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [first, setFirst] = React.useState(step);
|
||||
const timeout = React.useRef(null);
|
||||
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
if (!!timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
timeout.current = setTimeout(() => fetchChoices(value), loadingTime);
|
||||
};
|
||||
|
||||
const fetchChoices = (value: string) => {
|
||||
const filteredChoices = choices.filter(
|
||||
suggestion =>
|
||||
!value ||
|
||||
suggestion.label.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
||||
);
|
||||
|
||||
setLoading(true);
|
||||
|
||||
timeout.current = setTimeout(() => {
|
||||
setFilteredChoices(filteredChoices);
|
||||
setLoading(false);
|
||||
setFirst(step);
|
||||
}, loadingTime);
|
||||
};
|
||||
|
||||
const handleFetchMore = () => {
|
||||
setLoading(true);
|
||||
|
||||
timeout.current = setTimeout(() => {
|
||||
setFilteredChoices(choices.slice(0, first + step));
|
||||
setLoading(false);
|
||||
setFirst(first + step);
|
||||
}, loadingTime);
|
||||
};
|
||||
|
||||
return [
|
||||
filteredChoices,
|
||||
{
|
||||
fetchChoices: handleChange,
|
||||
hasMore: choices.length > filteredChoices.length,
|
||||
loading,
|
||||
onFetchMore: handleFetchMore
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export const ChoiceProvider: React.FC<ChoiceProviderProps> = ({
|
||||
children,
|
||||
choices
|
||||
}) => {
|
||||
const [filteredChoices, opts] = useMockChoiceProvider(choices);
|
||||
|
||||
return children({
|
||||
choices: filteredChoices,
|
||||
...opts
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue