React HOC TypeScript избавляется от любого типа с помощью Redux connect

#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);
};