我想一起使用react-hooks和rxjs中的useReducer。 例如,我想从 API 获取数据。
这是我为此编写的代码:
RXJS Hook :
function useRx(createSink, data, defaultValue = null) {
const [source, sinkSubscription] = useMemo(() => {
const source = new Subject()
const sink = createSink(source.pipe(distinctUntilChanged()));
const sinkSubscription = sink.subscribe()
return [source, sinkSubscription]
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(() => {
source.next(data)
}, [source, data])
useEffect(() => {
return () => {
sinkSubscription.unsubscribe()
};
}, [sinkSubscription])
}
reducer 代码:
const dataFetchReducer = (state, action) => {
switch (action.type) {
case 'FETCH_LOADING':
return {
...state,
loading: true
};
case 'FETCH_SUCCESS':
return {
...state,
loading: false,
total: action.payload.total,
data: action.payload.data
};
case 'FETCH_FAILURE':
return {
...state,
error: action.payload
};
case 'PAGE':
return {
...state,
page: action.page,
rowsPerPage: action.rowsPerPage
};
default:
throw new Error();
}
};
我如何混合它们:
function usePaginationReducerEndpoint(callbackService) {
const defaultPagination = {
statuses: null,
page: 0,
rowsPerPage: 10,
data: [],
total: 0,
error: null,
loading: false
}
const [pagination, dispatch] = useReducer(dataFetchReducer, defaultPagination)
const memoPagination = useMemo(
() => ({
statuses: pagination.statuses,
page: pagination.page,
rowsPerPage: pagination.rowsPerPage
}),
[pagination.statuses, pagination.page, pagination.rowsPerPage]
);
useRx(
memoPagination$ =>
memoPagination$.pipe(
map(memoPagination => {
dispatch({type: "FETCH_LOADING"})
return memoPagination
}),
switchMap(memoPagination => callbackService(memoPagination.statuses, memoPagination.page, memoPagination.rowsPerPage).pipe(
map(dataPagination => {
dispatch({ type: "FETCH_SUCCESS", payload: dataPagination })
return dataPagination
}),
catchError(error => {
dispatch({ type: "FETCH_SUCCESS", payload: "error" })
return of(error)
})
))
),
memoPagination,
defaultPagination,
2000
);
function handleRowsPerPageChange(event) {
const newTotalPages = Math.trunc(pagination.total / event.target.value)
const newPage = Math.min(pagination.page, newTotalPages)
dispatch({
type: "PAGE",
page: newPage,
rowsPerPage: event.target.value
});
}
function handlePageChange(event, page) {
dispatch({
type: "PAGE",
page: page,
rowsPerPage: pagination.rowsPerPage
});
}
return [pagination, handlePageChange, handleRowsPerPageChange]
}
代码有效,但我想知道这是否是运气......
- 如果我在 RXJS 管道内调度可以吗?有什么风险?
- 如果不是,我如何混合使用 useReducer 和 RXJS ?
- 如果这不是好方法,那么什么是好方法?
我知道这个资源:https://www.robinwieruch.de/react-hooks-fetch-data/ 。但我想混合使用 hooks 和 RXJS 的强大功能,以便在异步请求中使用 debounce 函数和 rxjs...
感谢您的帮助,
最佳答案
您所需要的只是一个中间件来连接 useReducer 和 rxjs,而不是自己创建一个。 使用useReducer会产生很多潜在的难以调试的代码,并且还需要一个独立的容器组件来放置useReducer以防止意外的全局重新渲染。
所以我建议使用 redux 放置 useReducer 从组件创建全局状态,并使用 redux-observable (基于 RxJS 6 的 Redux 中间件)作为连接 rxjs 和 redux 的中间件。
如果你熟悉rxjs,它会非常容易使用,正如官网所示,从api获取数据将是: https://redux-observable.js.org/docs/basics/Epics.html
// epic
const fetchUserEpic = action$ => action$.pipe(
ofType(FETCH_USER),
mergeMap(action =>
ajax.getJSON(`https://api.github.com/users/${action.payload}`).pipe(
map(response => fetchUserFulfilled(response))
)
)
);
关于rxjs - 如何将 useReducer 和 rxjs 与 React hooks 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56508716/