Как правильно перенести подключенный компонент из класса на функциональный компонент на TS? - PullRequest
1 голос
/ 12 июля 2019

Я пытаюсь перейти с компонента на основе класса на функциональный компонент.Это подключенный компонент, использующий mapState.

Вот что у меня было:

import { connect } from 'react-redux'
import { fetchArticles } from '../shared/actions/articleActions';
import { AppState } from '../shared/types/genericTypes';
import Article from '../shared/models/Article.model';

type Props = {
  articles?: Article[]
  fetchArticles?: any,
};

const mapState = (state: AppState, props) => ({
  articles: state.articleReducers.articles,
  ...props
});

const actionCreators = {
  fetchArticles,
};

class NewsArticles extends Component<Props> {
  componentDidMount() {
    if (!this.props.articles || !this.props.articles.length) {
      this.props.fetchArticles();
    }
  }

  render() {
    return (...);
  }
}

export default connect(mapState, actionCreators)(NewsArticles)

Вот что у меня сейчас:

// same imports except for FC and useEffec from react.

type Props = {
  articles?: Article[];
  fetchArticles?: any;
};

const mapState = (state: AppState, props: Props) => ({
  articles: state.articleReducers.articles,
  ...props,
});

const actionCreators = {
  fetchArticles,
};

const NewsArticles: FC<Props> = ({ articles, fetchArticles }) => {
  useEffect(() => {
    if (!articles || !articles.length) {
      fetchArticles();
    }
  }, []);

  return (...);
};

export default connect(mapState, actionCreators)(NewsArticles);

Основная проблемаУ меня есть реквизиты.

Раньше они были такими

const mapState = (state: AppState, props) => ({
  articles: state.articleReducers.articles,
  ...props
});

И использовались вот так:

 componentDidMount() {
    if (!this.props.articles || !this.props.articles.length) {
      this.props.fetchArticles();
    }
  }

Теперь, когда у меня есть функциональный компонент, яполучить это

const mapState = (state: AppState, props: Props) => ({
  articles: state.articleReducers.articles,
  ...props,
});

И использовать так:

  useEffect(() => {
    if (!articles || !articles.length) {
      fetchArticles();
    }
  }, []);

Так как props будет работать теперь, когда articles и fetchArticles не называются как this.props.articles и толькоarticles так, имеет ли смысл выкладывать реквизит …props на mapState?

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Ваш код компилируется, но не полностью корректен с сигнатурой функции connect.Давайте посмотрим на подпись

<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>(
    mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
    mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;

. Имеет 4 типа:

  1. TSTateProps - тип реквизита, полученный из состояния Redux.В вашем примере это

    type StateProps = {
        articles: Article[];
    }
    

    Только articles являются производными от состояния Redux.

  2. TDispatchProps - это тип реквизита, содержащий действия, которые ваш компонент будет отправлять.Поскольку вы передаете actionCreators объект connect TDispatchProps должен равняться typeof actionCreators (мы должны получить тип объекта actionCreators).

  3. TOwnProps - это типреквизиты ваш компонент получить от родителя (не из Redux).Вы не используете реквизиты от родителя, поэтому TOwnProps будет равно {}.

  4. TState - это тип состояния в Redux.Это AppState.

Так что, чтобы быть полностью корректным с Redux, вы должны сделать

type StateProps = {
    articles: Article[];
};

const mapState = (state: AppState): StateProps => ({
    articles: state.articleReducers.articles
});

const actionCreators = {
    fetchArticles,
};

type Props = StateProps & typeof actionCreators;  // These is correct props for your component

const NewsArticles: FC<Props> = ({ articles, fetchArticles }) => {

И на случай, если позже вы добавите реквизиты из родителя,просто пересекайте их с Props.

type Props = StateProps & typeof actionCreators & OwnProps;

Ваш код работал, когда вы добавили ...props к mapStateprops содержал член fetchAction.Таким образом, вы, наконец, получили тот же Props, как я показал в своем ответе, но немного неправильный.

0 голосов
/ 12 июля 2019

Нет необходимости распространять реквизиты в mapState.

Это:

const mapState = (state: AppState, props: Props) => ({
  articles: state.articleReducers.articles,
  ...props,
});

эквивалентно этому:

const mapState = (state: AppState) => ({
  articles: state.articleReducers.articles,
});

Любые дополнительные реквизиты получатпередается в ваш компонент в дополнение к реквизитам из mapState и mapDispatch (которые вы назвали actionCreators).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...