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



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

那么,既然articlesfetchArticles不像this.props.articles那样被称为,只有这样articles,那么props将如何工作,在mapState上传播道具…props有什么意义吗?

没有必要在mapState中传播道具。

这:

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

相当于这个:

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

除了来自mapStatemapDispatch的 props(您称之为actionCreators)之外,任何额外的 props 都会传递到您的组件中。

您的代码是可编译的,但使用函数签名并不完全正确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对象传递给connectTDispatchProps应该等于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;

您的代码在向mapState添加...props时工作。props包含成员fetchAction.所以你终于得到了与我在答案中显示的相同的Props,但略有错误。

相关内容

最新更新