[英]How to correctly use 'connect' in react-redux with Typescript
I'm using typescript in an application, but found some problem with react-redux.我在应用程序中使用打字稿,但发现 react-redux 存在一些问题。 The 'connect' method reports a problem and I have no idea with it since I'm a rookie with typescript and redux.
'connect' 方法报告了一个问题,我不知道它,因为我是一个打字稿和 redux 的新手。 What should I do or where in my code should be modified?
我应该怎么做或应该修改代码中的哪些地方? Thanks a lot
非常感谢
Application built with typescript@3.3
, react@16.8.5
, react-redux@7.1.0
.应用内置
typescript@3.3
, react@16.8.5
, react-redux@7.1.0
。
// article
interface IArticle {
title: string,
author: string
}
// state
interface MyState {
list: [],
article: IArticle
}
// stateMapToProps
interface MyStateProps {
article: IArticle
}
// router match
interface MatchParams {
id: string
}
// own props
interface MyOwnProps extends RouteComponentProps < MatchParams > {
article: IArticle,
dispatch: (o: object) => {}
}
class ArticleContainer extends Component < MyOwnProps, {} > {
constructor(props: MyOwnProps) {
super(props);
}
componentDidMount() {
const {
dispatch
} = this.props;
const id = this.props.match.params.id
dispatch(fetchArticle(id))
}
render() {
const {
article
} = this.props;
return ( <
Article article = {
article
} > < /Article>
)
}
}
const mapStateToProps = (state: MyState): MyStateProps => {
return {
article: state.article
}
}
export default connect < MyStateProps, {}, {
article: IArticle
} > (
mapStateToProps
)(ArticleContainer)
Here is the code of async action fetchArticle
这是异步操作
fetchArticle
的代码
function fetchArticle(id: string) {
return function(dispatch: (action: AnyAction) => {}): Promise<void> {
dispatch(getArticle(id))
return axios.get(`/article/${id}`)
.then(res => {
dispatch(getArticleSuccess(res.data))
})
}
}
Error happens at the export
line and message is as below: export
行发生错误,消息如下:
Argument of type '(state: MyState) => MyStateProps' is not assignable to parameter of type 'MapStateToPropsParam'.
“(state: MyState) => MyStateProps”类型的参数不可分配给“MapStateToPropsParam”类型的参数。 Type '(state: MyState) => MyStateProps' is not assignable to type 'MapStateToPropsFactory'.
类型 '(state: MyState) => MyStateProps' 不可分配给类型 'MapStateToPropsFactory'。 Types of parameters 'state' and 'initialState' are incompatible.
参数“state”和“initialState”的类型不兼容。 Type '{}' is missing the following properties from type 'MyState': list, articlets(2345)
类型“{}”缺少类型“MyState”中的以下属性:list、articlets(2345)
Minimum steps to be able to compile your code:能够编译代码的最低步骤:
MyOwnProps
should be MyOwnProps
应该是
import { AnyAction } from 'redux'; interface AppThunkAction<TAction> { (dispatch: (action: TAction) => void, getState: () => MyState): any; } // As you're going to dispatch thunk actions, dispatch should be overloaded interface Dispatch<TAction> { (action: AppThunkAction<TAction>): any (action: TAction): TAction } // own props interface MyOwnProps extends RouteComponentProps<MatchParams> { article: IArticle, dispatch: Dispatch<AnyAction> }
If you want to provide types for connect
function, add MyState
as last type like so如果要为
connect
函数提供类型,请将MyState
添加为最后一个类型,如下所示
export default connect <MyStateProps, {}, { article: IArticle }, MyState >( mapStateToProps )(ArticleContainer)
Or you can allow compiler to infer types itself, which is preferred或者您可以允许编译器自行推断类型,这是首选
export default connect( mapStateToProps )(ArticleContainer)
So working result所以工作结果
import { Component } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { connect, ResolveThunks } from 'react-redux';
import { AnyAction } from 'redux';
import axios from 'axios';
// article
interface IArticle {
title: string,
author: string
}
// state
interface MyState {
list: [],
article: IArticle
}
// stateMapToProps
interface MyStateProps {
article: IArticle
}
// router match
interface MatchParams {
id: string
}
export interface AppThunkAction<TAction> {
(dispatch: (action: TAction) => void, getState: () => MyState): any;
}
interface Dispatch<TAction> {
(action: AppThunkAction<TAction>): any
(action: TAction): TAction
}
// own props
interface MyOwnProps extends RouteComponentProps<MatchParams> {
article: IArticle,
dispatch: Dispatch<AnyAction>
}
function getArticle(id: string) {
return {
type: 'GET_ARTICLE',
id
}
}
function getArticleSuccess(i: any) {
return {
type: 'SET_ARTICLE',
i
}
}
const fetchArticle = (id: string): AppThunkAction<AnyAction> =>
(dispatch, getState) => {
dispatch(getArticle(id))
return axios.get(`/article/${id}`)
.then(res => {
dispatch(getArticleSuccess(res.data))
})
}
class ArticleContainer extends Component<MyOwnProps, {}> {
constructor(props: MyOwnProps) {
super(props);
}
componentDidMount() {
const {
dispatch
} = this.props;
const id = this.props.match.params.id
dispatch(fetchArticle(id))
}
render() {
const {
article
} = this.props;
return (<div>article: {article}</div>
)
}
}
const mapStateToProps = (state: MyState): MyStateProps => {
return {
article: state.article
}
}
export default connect(
mapStateToProps
)(ArticleContainer)
Here is a working example, how to type a react file when using redux, based on your example.这是一个工作示例,根据您的示例,如何在使用 redux 时键入 react 文件。
// article-container.js file
import { connect, DispatchProp } from "react-redux";
import { Component } from "react";
// import the real RouteComponent, this is just a demo example
interface RouteComponentProps<T> {
match: { params: T };
}
// article
interface IArticle {
title: string;
author: string;
}
// import the real Article, this is just a demo example
const Article = ({ article }: { article: IArticle }) => {
return <div>{article.title}</div>;
};
// import the real fetchArticle, this is just a demo example
const fetchArticle = (id: string) => {
return {
type: "SOME_ACTION",
payload: {
id,
},
};
};
// state
interface MyState {
list: [];
article: IArticle;
}
// stateMapToProps
interface MyStateProps {
article: IArticle;
}
// router match
interface MatchParams {
id: string;
}
// own props
interface MyOwnProps {
article: IArticle;
}
type AllProps = MyOwnProps & RouteComponentProps<MatchParams> & DispatchProp;
class ArticleContainer extends Component<AllProps> {
constructor(props: AllProps) {
super(props);
}
componentDidMount() {
const { dispatch } = this.props;
const id = this.props.match.params.id;
dispatch(fetchArticle(id));
}
render() {
const { article } = this.props;
return <Article article={article} />;
}
}
const mapStateToProps = (state: MyState): MyStateProps => {
return {
article: state.article,
};
};
export default connect(
mapStateToProps
)(ArticleContainer);
And use it like so并像这样使用它
import ArticleContainer from "./article-container";
export default () => {
// this is coming from router, just an example for demonstration
const match = { params: { id: "23" } };
return (
<div>
<ArticleContainer match={match} />
</div>
);
};
Finally solved with remove the generics declaration of connect
method and use ThunkDispatch
with async action creator.最后通过删除
connect
方法的泛型声明并使用ThunkDispatch
与异步操作创建者解决。 The code is below.代码如下。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ThunkDispatch } from 'redux-thunk';
import { fetchArticle } from '../store/actions';
import { RouteComponentProps } from 'react-router-dom';
import Article from '../components/Article/Article'
import { AnyAction } from 'redux';
// article
interface IArticle {
title: string,
author: string
}
// state
interface MyState {
list: [],
article: IArticle
}
// stateMapToProps
interface StateToProps {
article: IArticle
}
// router match
interface MatchParams {
id: string
}
// own props
interface MyOwnProps extends RouteComponentProps<MatchParams> {
article: IArticle,
getArticle: (id: string) => Promise<void>
}
class ArticleContainer extends Component<MyOwnProps, {}> {
constructor(props: MyOwnProps) {
super(props);
}
componentDidMount() {
const { getArticle } = this.props;
const id = this.props.match.params.id
getArticle(id)
}
render() {
const { article } = this.props;
return (
<Article article={article}></Article>
)
}
}
const mapStateToProps = (state: MyState): StateToProps => {
return {
article: state.article
}
}
const mapDispatchToProps = (dispatch: ThunkDispatch<any, any, AnyAction>) => {
return {
getArticle: (id: string) => dispatch(fetchArticle(id))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ArticleContainer)
Thanks for the help!谢谢您的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.