问题描述
一般想法是提供翻译功能的包装器组件。
顺便说一句,完整示例在此处https://codesandbox.io/s/quizzical-hellman-v84ed或GitHub https://github.com/hitrov/translation-wrapper
这是HOC签名
export const wrapper = <P extends object>(Component: React.ComponentType<P>) =>
(props: P & WithReplacementProps & 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,});
问题是,当我尝试用可以安全检查类型的内容替换<any>
时,总是会遇到TypeScript错误。
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 && translatedProps.header}</h1>
<p>{translatedProps && translatedProps.content}</p>
</>
);
}
解决方法
这就是我当前连接的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> &
typeof dispatchProps & {
// here you can extend ConnectedHoc with new props
// overrideCount?: number;
};
const Hoc = (props: PropsFromRedux & 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);
};