React Typescript:将位置状态添加到React路由器组件

16

我有一条常规路线

function LoginPage(props: RouteComponentProps): React.ReactElement {...
}

该组件使用来自react-router-dom的RouteComponentProps。

奇怪的是,很长一段时间以来,这个组件没有任何问题,但现在当我使用history.push(location.state.from.pathname)时,在travis-ci上编译失败,显示 "类型'{}'上不存在属性'from'"。

我在我的PrivateRoute组件中设置了这个状态,它与Redirect非常标准。

<Redirect
  to={{ pathname: '/login', state: { from: props.location } }}
/>

如何更新location的输入以包括一个带有pathname: string;from对象?

编辑:

解决方案是在将package.json复制后,将

COPY yarn.lock /usr/src/app/

添加到我的Dockerfile中。


1
由于 https://github.com/DefinitelyTyped/DefinitelyTyped/issues/41674 引起的问题。 - danielnixon
8个回答

34
你可以使用useLocation()钩子提供一个通用类型,这样你就可以覆盖默认设置在location.state中的unknown类型。
import { RouteComponentProps, useLocation } from 'react-router-dom';
import React from 'react';

interface stateType {
   from: { pathname: string }
}

const { state } = useLocation<stateType>();

console.log(state.from)

它应该可以正常工作。


这似乎比使用 RouteComponentProps 的第三个泛型参数来定义状态类型要容易得多。谢谢。 - ErikAGriffin

30

过去,位置状态的类型检查是被禁用的。这种情况在https://github.com/DefinitelyTyped/DefinitelyTyped/issues/41674中有所改变。

该类型默认为unknown,但你可以使用泛型来更改它:

import { Location } from 'history';
import { ReactElement } from 'react';
import { StaticContext } from 'react-router';
import { RouteComponentProps } from 'react-router-dom';

type LocationState = {
    from: Location;
};

function LoginPage(
    props: RouteComponentProps<{}, StaticContext, LocationState>,
): ReactElement {
    props.history.push(props.location.state.from.pathname);
}

4

看起来您没有为包使用锁定文件。我建议您找到一个工作环境(在以前生成的Docker镜像中或来自团队成员之一),并在那里生成package-lock.json(或yarn.lock)。我用以下命令生成它:npm install --package-lock。这将有助于解决第一次问题,直到完全解决。


6
也许我没看懂重点在哪里,但这个回答如何回答问题呢? - pzaenger
@pzaenger 这确实回答了如何修复编译失败的问题,但正如我之前所说,这只是一个临时解决方案。 - aLLeXUs
1
天啊,你的猜测几乎完全正确。在我的 Dockerfile 中,我在复制 package.json 后添加了 COPY yarn.lock /usr/src/app/,这解决了问题。 - peter
我曾经遇到过同样的问题。我不小心在使用 npm 作为包管理器的旧项目中使用了 yarn。然后 yarn 创建了一个新的锁定文件。问题就出现了。谢谢,感谢你的帮助解决这个问题。 - Prakhil TP

3

它的功能非常好

const { valueX, valueY } = location.state as any;

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

3

我受益于@Oliver Joseph Ash的答案,但由于我使用了connected-react-router,它没有导出成员,因此可能无法访问StaticContext,但我没有深入研究。

我像这样创建了一个模拟类型:

import { RouteComponentProps } from 'react-router-dom';

type LocationState = {
  // ... type of members passed to state
};

type MockType = {
  [key: string]: string | undefined;
};

type TypeWithLocationState = RouteComponentProps<MockType, MockType, LocationState>;

这个对我有用。


1
import * as H from "history";
const location: H.Location = useLocation();

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

为了进一步解释@Francisco Baralle的答案

当状态可能未定义时(例如从另一个不包含状态的位置重定向)。可以使用:

 useLocation<stateProps | undefined>

然后进行检索

 const stateValue = location.state?.stateValue   

然后在未定义的情况下处理逻辑


-1

虽然来晚了,但这是我解决问题所使用的过程。

浏览器或React的类型附带了一个名为history的通用类型,其中包含位置属性的类型,并添加缺失的类型,例如"from",使我能够无问题地使用位置状态,但请参见下面的示例。

//types.ts
import { RouteProps } from 'react-router';

//useHistory props
export interface useHistoryProps {
  from: string;
}

然后在我的主文件中

//main.tsx
import { History } from 'history';

const history: History<useHistoryProps> = useHistory();

请在您的回答中添加适当的归属。从我所看到的情况来看,这似乎是您从 YouTube 视频的转录中复制而来,没有给作者以功劳(我已经将您回答中的 YouTube 部分删除)。 - Spikatrix
不,或者你的意思是Youtuber从这里得到了它?如果你能向我展示这是从哪里复制的,我会做出必要的处理。Youtube评论被用作一个笑话。 - ibenge uforo
抱歉,我没有看出YouTube评论是个笑话。当我看到时,我以为你是从视频文本中复制了答案的内容。顺便说一下,我不是那个给你点踩的人,但我也不会撤销我的编辑,因为YouTube评论与答案无关。 - Spikatrix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接