в моем приложении реагирования я хотел бы скрыть реализацию избыточности от View logi c в своем собственном пакете «я называю это пакетом sdk», и я экспортирую множество хуков реакции из пакета sdk, чтобы его мог использовать любой клиент.
Вопрос вкратце.
const fetch = (params) => (dispatch) => api.get('/media', params);
как я могу сказать машинописи пропустить thunk и иметь дело с возвращаемым значением функции thunk у меня есть объект Record, как его набрать пропустить среднюю функцию?
Контекст
код:
// hook.tsx
import * as actions from './actions'; // thunks
import * as selectors from './selectors'; // reselect.
import {useSelector, useDispatch} from 'react-redux';
export function useMedia(): [Selectors<typeof selectors>,Actions<typeof actions>] {
// use ref to cache hook
return useRef([
bindSelectors(selectors, useSelector),
bindDispatch(actions, useDispatch()),
]).current;
}
теперь внутри моих представлений, когда мне нужно использовать этот фрагмент мультимедиа, который я использую.
import { useMedia } from '@sdk/media'
// ....
const [media, mediaActions] = useMedia();
// dispatch an action
mediaActions.fetch({limit:10}).then(console.log);
// select a slice using selector
const photos = media.photosOfAlbum(1);
мои взгляды не знают / не заботятся о том, как работает useMedia, так что я мог бы реально разделить обязанности внутри моей кодовой базы и упростить совместное использование кодов, тестирование и т. Д. c .., так как переключение реализации в любое время не затрагивает потребителей sdk ( Mobile / WebApp / даже nodejs приложения) никто не знает, что Redux использует питание SDK.
Проблема в том, что я не могу правильно набрать эти хуки .. (useMedia).
, поэтому мы имеем 2 вещи, чтобы ты здесь функция bindSelectors и функция bindDispatch.
bindSelectors
code
// @sdk/utils
function bindSelectors <T extends object>(selectors:T, useSelector): CurriedFunctionObject<T>{
return new Proxy(selectors, {
get: (main: T, key: keyof T, ctx: any) => {
const fn = Reflect.get(main, key, ctx);
// always inject store as first prop of fn
// we get store arg from useSelector higher order (its already properly typed)
return (props?: any) => useSelector(store => fn(store, props));
},
}
, которую я использовал для базового взлома прямого вызова объекта селектора, если всегда сохраняется первый аргумент arg.
export type CurriedFunctionObject<T> = {
[P in keyof T]: T[P] extends (
s: import('../rootReducer').AppState,
...p: infer Ps
) => infer R
? (...p: Ps) => R
: never;
};
теперь мои селекторы связаны и напечатаны, моя главная проблема заключается в том, как написать тип действий ..
bindDispatch
он работает во многом как bindSelectors. и я использую ActionCreatorsMapObject из 'redux-thunk', чтобы напечатать его
export function bindDispatch<T extends Record<string, any>>(
obj: T,
dispatch: Dispatch,
): ActionCreatorsMapObject<T> {
return new Proxy(obj, {
get: (main: T, key: keyof T, ctx) => {
const fn = Reflect.get(main, key, ctx);
return (...props: any[]) => dispatch(fn(...props));
},
});
}
Проблема с bindDispatch: -
, если я отправляю thunk, который возвращает обещание, он не введен правильно ..
пример выше код media.fetch({limit:10}).then///.then is will give error
Свойство 'catch' не существует для типа '(отправка: любая, getState: любая, {}: {}) => любая'`
, так что в основном, так как действие извлечения выглядит следующим образом
const fetch = (params) => (dispatch) => api.get('/media', params);
, поэтому оно ожидает функцию (dispatch)
, так как я могу сказать, что typcript пропускает thunk и обрабатывает возвращаемое значение функции thunk