React路由器dom和TypeScript



我还是typeScript的新手,所以我想做的是:

我有一个功能组件,我试图使用History.push从它导航到另一个,所以我尝试使用的模式是这样的:

history.push({
to: "some URL",
state: {// some state}
})

所以它似乎不起作用,这是我的父组件(我正试图从中导航)

import React from 'react';
import { VideoDataType } from '../Shared/VideoDataType/VideoDataType';
import { Options } from 'react-youtube';
import moment from 'moment';
import { useHistory, withRouter, RouteComponentProps } from 'react-router-dom';
import './VideoCard.styles.css';
interface ChildComponentProps extends RouteComponentProps<any> {
/* other props for ChildComponent */
video: VideoDataType;
opts: Options;
}
const VideoCard = ({
video,
opts,
}: ChildComponentProps): React.ReactElement => {
const history = useHistory();
const handleVideoSelect = (): void => {
history.push({
to:`/video/${video.id.videoId}`,
state: {video, opts}
});
};
return (
<div
className='videoCArd__wrapper fix_margins'
onClick={() => handleVideoSelect()}
>
<img src={video.snippet.thumbnails.medium.url} alt='avatar' />
<div className='videoCard__info'>
<div className='videoCard__text'>
<h4 className='videoCard__title'> {video.snippet.title}</h4>
<div className='videoCard__headline'>
<p> {video.snippet.channelTitle} &#9679; </p>
<p> {moment(video.snippet.publishedAt).fromNow()} </p>
</div>
<div className='videoCard__description'>
{video.snippet.description}
</div>
</div>
</div>
</div>
);
};
export default withRouter(VideoCard);

这是我的目标组件(现在我正在导航到)

import React from 'react';
import { Options } from 'react-youtube';
import { VideoDataType } from '../Shared/VideoDataType/VideoDataType';
import { RouteComponentProps, withRouter } from 'react-router-dom';
interface ChildComponentProps extends RouteComponentProps<any> {
/* other props for ChildComponent */
}
const SingleVideoDisplayerPage =
(): React.ReactElement<ChildComponentProps> => {
return (
<div>
<h6> jksdgfdsghjfkd </h6>
</div>
);
};
export default withRouter(SingleVideoDisplayerPage);

问题是:

No overload matches this call.
Overload 1 of 2, '(path: string, state?: unknown): void', gave the following error.
Argument of type '{ to: string; state: { video: VideoDataType; opts: Options; }; }' is not assignable to parameter of type 'string'.
Overload 2 of 2, '(location: LocationDescriptor<unknown>): void', gave the following error.
Argument of type '{ to: string; state: { video: VideoDataType; opts: Options; }; }' is not assignable to parameter of type 'LocationDescriptor<unknown>'.
Object literal may only specify known properties, and 'to' does not exist in type 'LocationDescriptorObject<unknown>'.  TS2769
20 |   const history = useHistory();
21 |   const handleVideoSelect = (): void => {
> 22 |     history.push({
|     ^
23 |       to: `/video/${video.id.videoId}`,
24 |       state: { video, opts },
25 |     });

问题出在VideoCard组件上。打字应该是这样的:

// This is a random typing I did to showcase the example.
type RouteState = {
video: {
id: number;
};
opts: {
required: boolean;
};
};
// This will be the type you will pass to the VideoCard component
// It receives the state we just did as the Third generic
type IVideoProps = RouteComponentProps<{}, StaticContext, RouteState>

之后,为了在组件中使用更高阶的组件,您需要使用正确的类型,因此基本上,HOC将每个react路由器属性作为道具,这就是为什么IVideoProps具有StaticContext和RouteState,因此您将这样调用它:

const VideoCard = ({ location: { state } }: IVideoProps) => {
// This condition needs to be here because the state can be undefined if you are not accessing the component via link or history.
if (!state) return null;
const { video } = state;
return (
<div>
<h2>Video</h2>
{video.id}
</div>
);
};
export default withRouter(VideoCard);

你遇到的问题是,如果你扩展RouteComponentProps,你需要将这些额外的道具分别传递给该组件,视频和opts,它们根本不会链接到路由器,它只是像你通常做的那样传递道具,只是这样做没有多大意义,因为你必须使用某种HOC来检索值,因为你不能使用链接或反应历史来传递它们。

最后但并非最不重要的是,我将建议使用useLocation挂钩,使键入更容易。

import { useLocation } from "react-router";
import { RouteState } from "./Router";
const VideoCard = () => {
const { state } = useLocation<RouteState>();
if (!state) return null;
const { video } = state;
return (
<div>
<h2>Video</h2>
{video?.id}
</div>
);
};
export default VideoCard;

您可以看到,使用hook只需要将State类型作为泛型参数const { state } = useLocation<RouteState>();传递,因此更容易。

这样打字就会正确,如果你有任何问题,可以随时查看沙盒:https://codesandbox.io/s/gifted-mclaren-opp0p

最新更新