有这么一个需求,有一个输入框,当用户在输入框中输入关键字时进行实时搜索,且最后返回结果匹配最后的输入词。
拆分一下需求,有这么几个关键点
- 实时自动搜索
- 结果匹配最后的关键词
再继续拆分,还需要以下几个点
- 节流:如果真的用户每输入一个词就发起一次搜索,将会非常发起无效的接口请求,因此需要做一个节流
- 竞态:请求结果返回的顺序不能保证一致。
debounce hook
const useDebounce = (initialValue, delay) => {
const [value, setValue] = useState(initialValue);
const debouncedSetValue = useRef(
debounce((val) => {
setValue(val);
}, delay)
);
useEffect(() => debouncedSetValue.current(initialValue), [initialValue]);
return [value];
};
fetchData hook
const useFectchData = (func, params, initialValue) => {
const [state, dispatch] = useReducer(
(state, action) => {
switch (action.type) {
case "FETCH_INIT":
return { ...state, isFetching: true, isError: false };
case "FETCH_SUCCESS":
return {
...state,
isFetching: false,
isError: false,
data: action.payload,
};
case "FETCH_FAILURE":
return {
...state,
isFetching: false,
isError: true,
};
}
},
{
isError: false,
isFetching: false,
data: initialValue,
}
);
const [debouncedParams] = useDebounce(params, 500);
useEffect(() => {
let didCancel = false;
const fetchData = async () => {
try {
dispatch({ type: "FETCH_INIT" });
const res = await func(params);
if (didCancel) return;
dispatch({ type: "FETCH_SUCCESS", payload: res });
} catch (_) {
dispatch({ type: "FETCH_FAILURE" });
}
};
fetchData();
return () => {
didCancel = true;
};
}, [debouncedParams]);
return [state];
};
组件
function App() {
const [searchParams, setSearchParams] = useState({
query: "react",
current: 1,
pageSize: 20,
});
const [{ data: searchResult, isFetching }] = useFectchData(
fetchData,
searchParams,
{}
);
const { tableData, pagination } = useMemo(() => {
const tableData = searchResult.data || [];
const pagination = {
current: (searchResult?.current || 0) + 1,
total: searchResult?.total || 0,
pageSize: searchResult?.pageSize || 20,
};
return { tableData, pagination };
}, [searchResult]);
const tableColumns = useMemo(() => {
return [
{ title: "标题", dataIndex: "title" },
{ title: "作者", dataIndex: "author" },
{
title: "发布时间",
dataIndex: "created_at",
render: (val) => dayjs(val).format("YYYY-MM-DD"),
},
];
}, []);
return (
<div>
<Input
style={{ width: 200, margin: 8 }}
value={searchParams.query}
onChange={(event) => {
setSearchParams({ ...searchParams, query: event.target.value });
}}
/>
<Button
style={{ display: "block" }}
loading={isFetching}
style={{ margin: 8 }}
onClick={() => {
setSearchParams({ ...searchParams });
}}
>
search
</Button>
<Table
pagination={{
...pagination,
onChange: (current, pageSize) => {
setSearchParams({
...searchParams,
current: current - 1,
pageSize,
});
},
}}
style={{ width: 1000, margin: 8 }}
bordered
rowKey="objectID"
loading={isFetching}
columns={tableColumns}
dataSource={tableData}
></Table>
</div>
);
}
参考
www.robinwieruch.de/react-hooks… overreacted.io/zh-hans/a-c…