使用“withRouter”和 Typescript 时出现类型问题
Posted
技术标签:
【中文标题】使用“withRouter”和 Typescript 时出现类型问题【英文标题】:issue with types when using "withRouter" and Typescript 【发布时间】:2019-11-20 13:42:49 【问题描述】:我正在尝试对 React+Typescript 进行更深入的了解和实践,在使用来自 react-router-dom
的 withRouter
时遇到了这个打字错误。
我的代码 sn-p 非常简单,我尝试找出有相同问题的人,其中一些答案指出升级时出错(但它们是从 2016 年开始的,所以......)和他们中的一些人使用了我没有使用的connect()
语句(这导致了一个问题,“我这样做是因为不使用它而做错了吗?”)。我看到其中一些建议还涉及将 Props 映射到 State,直到现在我还没有做过(也没有见过)。我希望有人对我缺少什么以及我应该查看的其他内容提出一些建议。
代码是:
import React from "react";
import withRouter from "react-router-dom";
interface ISection
id: number;
title: string;
imageUrl: string;
size: string;
class MenuItem extends React.Component<ISection>
render()
return (
<div className=`$this.props.size menu-item`>
<div
className="background-image"
style= backgroundImage: `url($this.props.imageUrl)`
/>
<div className="content">
<h1 className="title">this.props.title</h1>
<span className="subtitle">some subtitle</span>
</div>
</div>
);
export default withRouter(MenuItem);
我期望从这里顺利工作(我不得不说我首先尝试了一个功能组件,因为我没有任何状态,但是我看到的所有解决方案都涉及一个类组件,所以我移动了它进入它),但我在最后一行的MenuItem
上收到以下错误:
Argument of type 'typeof MenuItem' is not assignable to parameter of type 'ComponentClass<RouteComponentProps<any, StaticContext, any>, any> | FunctionComponent<RouteComponentProps<any, StaticContext, any>> | (FunctionComponent<RouteComponentProps<any, StaticContext, any>> & ComponentClass<...>) | (ComponentClass<...> & FunctionComponent<...>)'.
Type 'typeof MenuItem' is not assignable to type 'ComponentClass<RouteComponentProps<any, StaticContext, any>, any>'.
Types of parameters 'props' and 'props' are incompatible.
Type 'RouteComponentProps<any, StaticContext, any>' is missing the following properties from type 'Readonly<ISection>': id, title, imageUrl, sizets(2345)
我的问题是:
为什么会显示“type 'typeof MenuItem'”?不应该只说'MenuItem'的类型而不是获取类型的函数吗?
withRouter 是否必须与类组件一起使用,还是对功能组件也有效?
我需要connect()
什么,或者将 Props 映射到 State 上吗?如果是,为什么?
最后,我该如何解决这个问题?
【问题讨论】:
【参考方案1】:从 documentation 开始,withRouter
将在渲染时将更新的 match
、location
和 history
道具传递给包装的组件。
所以MenuItem
组件应该有道具来接收它们。目前,MenuItem
组件的 props 类型为 ISection
,不包括路由器 props。
添加路由器道具的最简单方法是将ISection
与RouteComponentProps
相交。
import withRouter, RouteComponentProps from "react-router-dom";
// ...
class MenuItem extends React.Component<ISection & RouteComponentProps>
完整代码是
import * as React from 'react';
import withRouter, RouteComponentProps from "react-router-dom";
interface ISection
id: number;
title: string;
imageUrl: string;
size: string;
class MenuItem extends React.Component<ISection & RouteComponentProps>
render()
return (
<div className=`$this.props.size menu-item`>
<div
className="background-image"
style= backgroundImage: `url($this.props.imageUrl)`
/>
<div className="content">
<h1 className="title">this.props.title</h1>
<span className="subtitle">some subtitle</span>
</div>
</div>
);
export default withRouter(MenuItem);
并回答您的问题
为什么说“type 'typeof MenuItem'”?不应该只说'MenuItem'的类型而不是获取类型的函数吗?
由类型不兼容引起的错误。 MenuItem
是类,而不是类型。要获取MenuItem
的类型,您应该使用typeof MenuItem
。所以typeof MenuItem
是类型。编译器正确地说,“输入typeof MenuItem
”。
withRouter 是否需要对类组件起作用,还是对函数组件也起作用?
允许与类组件和功能组件一起使用。
这就是你的组件在实现为函数式时的样子
const Cmp1: React.FunctionComponent<ISection & RouteComponentProps> = (props) =>
return (
<div className=`$props.size menu-item`>
<div
className="background-image"
style= backgroundImage: `url($props.imageUrl)`
/>
<div className="content">
<h1 className="title">props.title</h1>
<span className="subtitle">some subtitle</span>
</div>
</div>
);
const WrappedCmp = withRouter(Cmp1);
我需要connect()
什么,或者将 Props 映射到 State 上吗?如果有,为什么?
不,这不是严格的要求。 connect
是 Redux 的一部分,所以如果你使用 Redux,你可以连接。这是documentation 如何使用withRouter
和connect
。但同样,它不是必需的。
最后,我该如何解决这个问题?
已经回答了。见上文:-)
【讨论】:
哇@Fyodor,这是我期待的最佳答案,非常感谢! 你不会相信这个问题有多少令人费解的答案,而这个是最简洁和格式正确的,@Fyodor 是赢家 @P.Gracia 哇哦!解释清楚【参考方案2】:对于任何来这里的人 Next.js 像这样将你的道具界面与 WithRouterProps 相交..
import WithRouterProps from "next/dist/client/with-router";
class MenuItem extends React.Component<IProps & WithRouterProps>
【讨论】:
以上是关于使用“withRouter”和 Typescript 时出现类型问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 connect 和 withRouter 包装组件的顺序是不是重要
输入一个同时使用 withRouter 和 connect 的 HOC 组件
带连接的 withRouter 在 v5.0.0 中不起作用?
withRouter 参数解析 Invariant Violation 时出错:您不应在 <Router> 之外使用 <Route> 或 withRouter()