[英]custom hooks for data fetch
我已經制作了這個自定義掛鈎來使用fetcher獲取數據並返回 state,其中包含要顯示在 antd 表中的數據(喜歡它們)。 我不確定這是使用鈎子的正確方法,我已經在我有疑問的代碼中添加了注釋。
import { useEffect, useReducer } from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import queryString from 'query-string'
const initialState = { data: [], loading: true };
const fetchData = (fetcher, params, dispatch) => {
//in this case i need to change my state to loading, the reducer will do the trick, but i fill this kinda triky, should i call the fatcher after the dispatch end using an effect?
dispatch({ type: 'FETCHING' })
fetcher({ ...params, page: params.page > 0 ? params.page - 1 : params.page }, response => dispatch({ type: 'DATA_RECEIVED', payload: response.data }));
return () => {
console.log('unmounting useGridDataFetch')
};
}
const handlePageChange = (page, history, location) => {
const qparams = queryString.parse(location.search)
const qs = Object.keys(qparams).map(key => key != 'page' ? `&${key}=${qparams[key]}` : '')
history.push(`${history.location.pathname}?page=${page}${qs.reduce((acc,val)=> acc + val , '')}`)
}
const useGridDataFetch = (fetcher, initialParams) => {
const location = useLocation()
const history = useHistory()
const params = { ...initialParams, ...queryString.parse(location.search) }
// to use history and location inside my reducer to change the querystring on page change, i had to put the reducer definition inside the body of the hook, is there a better way?
const reducer = (state, action) => {
switch (action.type) {
case 'FETCHING':
return { loading: true };
case 'DATA_RECEIVED':
const pagination = {
pageSize: action.payload.pageable.pageSize,
current: action.payload.pageable.pageNumber + 1,
total: action.payload.totalElements,
onChange: page => handlePageChange(page, history, location)
}
return { dataSource: action.payload.content, loading: false, pagination };
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => fetchData(fetcher, params, dispatch), [location.search])
return [state, (_params) => fetchData(fetcher, { ...params, ..._params }, dispatch)]
}
export default useGridDataFetch
一般來說,你可以給我的每一個改進我的代碼的提示都會很感激。
謝謝。
我會盡力幫助你
首先,您必須從鈎子中提取減速器。 reducer
function 應該獨立於鈎子,因為useReducer(reducer, initialState);
僅使用這 2 個參數reducer
和initialState
一次,並且不會在每次下一次調用時更新它。 因此,您不能在 reducer 中使用handlePageChange
方法。
第二點是您的減速器必須返回具有相同接口的數據,例如{ data: Array, isLoading: Boolean }
。 In your case, you have 3 different response from reducer: after init - { data: Array, loading: Boolean }
, after FETCHING
- { loading: Boolean }
, and after DATA_RECEIVED
- { dataSource: Object, loading: Boolean, pagination: Object }
我建議你不要使用 useReducer。 我將建議我實現您的代碼
const useGridDataFetch = (fetcher, initialParams) => {
const { data, isLoading } = useGetData(fetcher, initialParams);
const { dataSource, pagination } = useGetPreparedData(data);
return {
isLoading,
dataSource,
pagination,
}
}
const useGetData = (fetcher, initialParams) => {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState({});
const location = useLocation();
useEffect(() => {
const params = {
...initialParams,
...queryString.parse(location.search)
}
setIsLoading(true);
fetcher({
...params,
page: params.page > 0 ? params.page - 1 : params.page
}, response => {
setData(response.data);
setIsLoading(false);
});
}, [location.search]);
return {
isLoading,
data
}
}
const useGetPreparedData = (data) => {
const location = useLocation();
const history = useHistory();
const handlePageChange = useCallback((page) => {
const qparams = queryString.parse(location.search);
const qs = Object.keys(qparams).map(key => key != 'page' ? `&${key}=${qparams[key]}` : '')
history.push(`${location.pathname}?page=${page}${qs.reduce((acc,val)=> acc + val , '')}`)
}, [location.pathname, location.search, history]);
return useMemo(() => {
if (!data.content) {
return {
dataSource: [],
pagination: {}
}
}
const pagination = {
pageSize: data.pageable.pageSize,
current: data.pageable.pageNumber + 1,
total: data.totalElements,
onChange: page => handlePageChange(page)
}
return {
dataSource: data.content,
pagination
};
}, [data, handlePageChange])
}
我可能對這段代碼有一些錯誤,但我認為主要思想很簡單
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.