如何正确地将连接的组件从基于类的组件迁移到TS上的功能组件?

时间:2019-07-12 01:32:53

标签: javascript reactjs typescript ecmascript-6 redux

我正在尝试从基于类的组件迁移到功能组件。它是使用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();
    }
  }, []);

既然propsarticles的调用方式不像fetchArticles,只有this.props.articles这样,articles的工作原理确实有意义…props上的mapState

2 个答案:

答案 0 :(得分:0)

无需在mapState中传播道具。

此:

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

等效于此:

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

除了mapStatemapDispatch(您称为actionCreators)中的道具之外,任何额外的道具都将传递到您的组件中。

答案 1 :(得分:0)

您的代码是可编译的,但使用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添加到mapState时,您的代码可以正常工作。并且props包含成员fetchAction。因此,您终于得到了与我在答案中显示的相同的Props,但略有错误。