rxjs - 如何将 useReducer 和 rxjs 与 React hooks 一起使用?

标签 rxjs react-hooks

我想一起使用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/

相关文章:

javascript - 类型 'catch' 上不存在属性 'Observable<any>'

angular - RXJS Observable 移除管道操作符

javascript - RxJS 在多个输出中拆分可观察序列

typescript - RXJS Angular - 使用 .subscribe 和 Observable 进行错误处理

arrays - TypeScript:输入带有值或空的数组/元组

reactjs - useMemo 可以用来在 React 页面中查找斐波那契数吗?

angular - 监视返回可观察对象的函数

reactjs - 正在重置的状态

javascript - 如何解决 Stripe 元素 react 导致重定向内存泄漏

reactjs - 停止重新渲染 react 功能组件