#reactjs #redux #react-redux #higher-order-functions #higher-order-components
#reactjs #redux #реагировать-redux #функции более высокого порядка #компоненты более высокого порядка
Вопрос:
Общая идея заключается в компоненте-оболочке, который обеспечивает возможность перевода.
Кстати, полный пример здесь https://codesandbox.io/s/quizzical-hellman-v84ed или GitHub https://github.com/hitrov/translation-wrapper
Вот СПЕЦИАЛЬНАЯ подпись
export const wrapper = <P extends object>(Component: React.ComponentType<P>) =>
(props: P amp; WithReplacementProps amp; IProps) => {...}
Компонент аргумента должен предоставлять содержимое с помощью
interface WithReplacementProps {
translatableProps: {
getHeader(): string;
getContent(): string;
}
}
Redux должен вводить
interface IProps {
language: string;
setLanguage(language: string): SetLanguage;
}
и вот как это делается
type StateProps = Pick<IProps, | 'language'>;
type DispatchProps = Pick<IProps, | 'setLanguage'>;
type OwnProps = Omit<
IProps,
keyof StateProps | keyof DispatchProps
>;
const connector = connect<StateProps, DispatchProps, OwnProps, RootState>((state: RootState) => ({
language: state.language,
}), {
setLanguage,
});
Проблема в том, что я всегда получаю ошибки TypeScript, когда пытаюсь заменить <any>
чем-то, что позволило бы безопасно проверять типы.
export function withReplacement<T>(Component: React.ComponentType<T>) {
return connector(wrapper<any>(Component));
}
вот, наконец, как я использую обернутый компонент
const ContentWithReplacement = withReplacement(Content);
...
<ContentWithReplacement
key={header}
header={header}
content={content}
translatableProps={{
getContent: () => content,
getHeader: () => header,
}}
/>
Компонент содержимого является прямым
export function Content(props: ContentProps) {
const { translatedProps } = props;
return (
<>
<h1>{translatedProps amp;amp; translatedProps.header}</h1>
<p>{translatedProps amp;amp; translatedProps.content}</p>
</>
);
}
Комментарии:
1.
import { ConnectedProps } from 'react-redux'; type PropsFromRedux = ConnectedProps<typeof connector>;
мне это тоже не помогло
Ответ №1:
Решена проблема. Это мне очень помогло https://github.com/piotrwitek/react-redux-typescript-guide#—nested-hoc—wrapping-a-component-injecting-props-and-connecting-to-redux-
Вот как выглядит мой подключенный HOC на данный момент
import React, { useReducer, useState } from "react";
import { reducer } from "../reducers";
import { Select } from "../Select";
import { connect } from 'react-redux';
import { RootState } from "../reducers/redux";
import { setLanguage, SetLanguage, } from '../reducers/language';
import { Diff } from 'utility-types';
interface InjectedProps {
language: string;
setLanguage(language: string): SetLanguage;
}
interface WithReplacementProps {
translatableProps: {
getHeader(): string;
getContent(): string;
}
}
export const withReplacement = <BaseProps extends {}>
(Component: React.ComponentType<BaseProps>) => {
const mapStateToProps = (state: RootState) => ({
language: state.language,
});
const dispatchProps = {
setLanguage: (language: string) => setLanguage(language),
};
type PropsFromRedux = ReturnType<typeof mapStateToProps> amp;
typeof dispatchProps amp; {
// here you can extend ConnectedHoc with new props
// overrideCount?: number;
};
const Hoc = (props: PropsFromRedux amp; WithReplacementProps) => {
const { translatableProps, language, setLanguage, ...rest } = props;
const [ showOriginal, setShowOriginal ] = useState(true);
const { getHeader, getContent } = translatableProps;
let header = getHeader();
let content = getContent();
const [ state, dispatch ] = useReducer(reducer, {...);
return (
<>
<Component
{...rest as BaseProps}
translatedProps={{
header,
content,
}}
/>
<Select
language={language}
onChange={e => {
setLanguage(e.target.value);
}}
/>
</>
);
};
return connect<ReturnType<typeof mapStateToProps>,
typeof dispatchProps, // use "undefined" if NOT using dispatchProps
Diff<BaseProps, InjectedProps>,
RootState>(
mapStateToProps,
dispatchProps
)(Hoc);
};