#typescript #redux #react-redux #typescript-typings #higher-order-functions
#typescript #redux #реагировать-redux #typescript-типизации #функции более высокого порядка
Вопрос:
Вот компонент, который при желании может отображать либо строку (не будучи подключенным к хранилищу Redux), либо поле выбора.
export function Content(props: ContentProps) {
const { language } = props;
if (!props.setLanguage) {
return (
<div>{language}</div>
);
}
return (
<Select
language={language}
languages={languages}
onChange={e => {
props.setLanguage!(e.target.value);
}}
/>
);
}
Этот код работает отлично
const mapStateToProps = (state: RootState) => ({
language: state.language,
});
const mapDispatch = {
setLanguage,
};
const connector = connect(mapStateToProps, mapDispatch);
const ConnectedContent = connector(Content);
function App() {
return (
<ConnectedContent />
);
}
Но дело в том, что мне понадобились бы дополнительные усовершенствования, поэтому соединитель должен быть повторно используемым, что-то вроде
//type PropsFromRedux = ConnectedProps<typeof connector>;
interface LoadingProps {
loading?: boolean;
}
const withLoading = <P extends {}>(Component: React.ComponentType<P>) => (props: P amp; LoadingProps) => (
<>
{props.loading amp;amp; <div>Loading</div>}
<Component {...props as P} />
</>
);
function getConnectedComponent(Component: React.ComponentType) {
const ComponentWithLoading = withLoading(Component);
return connector(ComponentWithLoading);
}
const ConnectedContent = getConnectedComponent(Content);
Но я не знаю, как правильно добавлять типы / обобщения в функцию getConnectedComponent. С выводом я получаю
Error:(24, 48) TS2345: Argument of type '(props: ContentProps) => Element' is not assignable to parameter of type 'ComponentType<{}>'.
Type '(props: ContentProps) => Element' is not assignable to type 'FunctionComponent<{}>'.
Types of parameters 'props' and 'props' are incompatible.
Property 'language' is missing in type '{ children?: ReactNode; }' but required in type 'ContentProps'.
Рабочий пример включен https://codesandbox.io/s/elegant-snowflake-b5r89
Также отправлено на GitHub https://github.com/hitrov/reusable-redux-connector
Ответ №1:
Я не уверен, что вы подразумеваете под «соединитель должен быть повторно используемым» или какие «дополнительные улучшения» вы имеете в виду. Он уже повторно используется. Функция, возвращаемая из connect(mapState, mapDispatch)
, готова принять любой компонент, который вы передали, поэтому он уже выполняет то, что ваш условный getConnectedComponent
хочет сделать.
Комментарии:
1. Привет, спасибо за ваш ответ, да, если я экспортирую эту переменную соединителя — это было бы. Но представьте, что мне понадобились бы дополнительные усовершенствования компонента перед передачей его соединителю (например, применить к нему HOC) — и вот почему у меня должна быть функция, которая получает component в качестве аргумента, а затем применяет к нему connector
2. Нет, никаких «улучшений», которые необходимы, и я не знаю, откуда вы взяли эту идею. Любой компонент может быть передан этой
connector()
функции, и она будет работать. Точка.3. вы говорите мне, что мне не нужно, пока я делаю =) я добавил приведенный выше пример — представьте, что мне нужно применить withLoading HOC до или после перехода к соединителю. есть ли какой-либо другой способ сделать это?
4. Такое использование
withLoading
HOC специфично для вашего собственного приложения. Я хочу сказать, что что касается React-Redux, то для успешного вызова больше ничего не нужно делатьconst ConnectedComponent = connector(MyComponent)
. На данный момент я не знаю, в чем собственно вопрос, tbh.