如何使用没有 <Link> 标签的 react-router-dom 发送参数

Posted

技术标签:

【中文标题】如何使用没有 <Link> 标签的 react-router-dom 发送参数【英文标题】:How to send params using react-router-dom without a <Link> tag 【发布时间】:2021-10-24 03:30:12 【问题描述】:

我正在使用 react-router-dom v^6.0.0-beta.1 和 React v^17.0.1,我通过点击卡片列表中的卡片从一页导航到另一页:

PlayersPage.tsx

/** @jsxImportSource @emotion/react */
import React,  useState, useEffect  from 'react';
import  Page  from './Page';
import  PageTitle  from './PageTitle';
import  Button, Card  from 'react-bootstrap';
import  css  from '@emotion/react';
import pic from '../assets/samurai.png';
import  useNavigate  from 'react-router';
import  Link  from 'react-router-dom';

function PlayersPage() 
  interface PlayersDataType 
    id: number;
    handle: string;
    role: string;
    avatar: string;
    specialAbilities: 
      playerId: number;
      authority: number;
      charismaticLeadership: number;
      combatSense: number;
      credibility: number;
      family: number;
      interface: number;
      juryRig: number;
      medicalTech: number;
      resources: number;
      streedeal: number;
    ;
    stats: 
      playerId: number;
      int: number;
      ref: number;
      tech: number;
      cool: number;
      attr: number;
      luck: number;
      ma: number;
      body: number;
      emp: number;
      run: number;
      leap: number;
      lift: number;
    ;
  

  //const [isLoading, setIsLoading] = useState<boolean>(false);
  const [playersData, setPlayersData] = useState<Array<PlayersDataType>>([]);
  const navigate = useNavigate();

  const createNew = () => 
    navigate('../Create');
  ;

  const handleSelect = () => 
    navigate('../Player');
  ;

  //Fetch all players from database
  useEffect(() => 
    //setIsLoading(true);
    fetch('https://localhost:44326/api/Players/all')
      .then((response) => 
        if (response.ok) 
          return response.json();
        
      )
      .then((data) => setPlayersData(data));
    //.then(setIsLoading(false));
  , []);

  return (
    <Page>
      <div>
        <PageTitle>Toons</PageTitle>
        <div
          css=css`
            justify-content: center;
            margin-left: 255px;
            margin-bottom: 10px;
          `
        >
          <button onClick=createNew>Create New</button>
        </div>
      </div>

      <div //Every card is listed in 1 column
        css=css`
          flex-direction: column;
          margin-left: 40px;
        `
      >
        playersData.map((data) => (
          <div key=data.id>
            <Card
              css=css`
                display: flex;
                width: 500px;
                height: 200px;
                flex-direction: column;
                //border: 2px solid black;
                box-shadow: 0 3px 7px 0 rgba(30, 38, 46, 0.21);
                cursor: pointer;
                :hover 
                  transform: scale(
                    1.2
                  ); /* (150% zoom - Note: if the zoom is too large, it will go outside of the viewport) */
                
              `
              onClick=handleSelect
            >
              <div
                css=css`
                  display: flex;
                  flex-direction: row;
                  //border: 2px solid orange;
                `
              >
                <Card.Img
                  src=pic
                  
                  css=css`
                    margin: 5px 10px 10px 10px;
                    width: 150px;
                    height: 150px;
                    border-radius: 50%;
                    box-shadow: 0 3px 7px 0 rgba(30, 38, 46, 0.21);
                    //border: 2px solid black;
                  `
                />
                <Card.Body
                  css=css`
                    flex: 1;
                    flex-direction: row;
                    //border: 2px solid purple;
                  `
                >
                  <div
                    css=css`
                      display: flex;
                      flex-direction: row;
                      //justify-content: space-between;
                      flex-wrap: wrap;
                    `
                  >
                    <Card.Text>Int:</Card.Text>
                    <Card.Text>data.stats.int</Card.Text>
                    <Card.Text>Ref:</Card.Text>
                    <Card.Text>data.stats.ref</Card.Text>
                    <Card.Text>Tech:</Card.Text>
                    <Card.Text>data.stats.tech</Card.Text>
                    <Card.Text>Cool:</Card.Text>
                    <Card.Text>data.stats.cool</Card.Text>
                    <Card.Text>Attr:</Card.Text>
                    <Card.Text>data.stats.attr</Card.Text>
                    <Card.Text>Luck:</Card.Text>
                    <Card.Text>data.stats.luck</Card.Text>
                    <Card.Text>Ma:</Card.Text>
                    <Card.Text>data.stats.ma</Card.Text>
                    <Card.Text>Body:</Card.Text>
                    <Card.Text>data.stats.body</Card.Text>
                    <Card.Text>Emp:</Card.Text>
                    <Card.Text>data.stats.emp</Card.Text>
                    <Card.Text>Run:</Card.Text>
                    <Card.Text>data.stats.run</Card.Text>
                    <Card.Text>Leap:</Card.Text>
                    <Card.Text>data.stats.leap</Card.Text>
                    <Card.Text>Lift:</Card.Text>
                    <Card.Text>data.stats.lift</Card.Text>
                  </div>
                </Card.Body>
              </div>
              <Card.Title
                css=css`
                  display: flex;
                  width: 150px;
                  flex-direction: row;
                  justify-content: center;
                  font-weight: bold;
                  margin-bottom: 10px;
                `
              >
                data.handle, data.role
              </Card.Title>
            </Card>
            <br></br>
          </div>
        ))
      </div>
    </Page>
  );


export default PlayersPage;

我想发送用户点击的任何卡片的data.id

有什么方法可以使用 onClick 函数在此处发送 data.id 作为参数:

  <div key=data.id>
            <Card
              css=css`
                display: flex;
                width: 500px;
                height: 200px;
                flex-direction: column;
                //border: 2px solid black;
                box-shadow: 0 3px 7px 0 rgba(30, 38, 46, 0.21);
                cursor: pointer;
                :hover 
                  transform: scale(
                    1.2
                  ); /* (150% zoom - Note: if the zoom is too large, it will go outside of the viewport) */
                
              `
              onClick=handleSelect
            >

并以某种方式将其发送到这里:

 const handleSelect = () => 
    navigate('../Player');
  ;

然后在另一个页面上使用该 id?

编辑:

这就是我现在正在尝试的:

onClick=() => handleSelect(data.id)

我认为这是正确的。然后在handleSelect函数中:

 const handleSelect = (id: number) => 
    history.push(pathname: '/Player',
      state:   
        id: id, 
      ,)
  

但是我在这方面遇到 3 个错误:Property 'push' does not exist on type 'History'.ts(2339)Cannot find name 'pathname'.ts(2304) 以及 state 的相同错误。

编辑 2:

我添加了 const history = useHistory();,并更新了handleSelect函数如下:

 const handleSelect = (id: number) => 
    history.push(
      pathname: '/Player',
      state: 
        id: id,
      ,
    );
  ;

除了打字稿错误Module '"react-router-dom"' has no exported member 'useHistory'.ts(2305)之外,一切似乎都很好。

【问题讨论】:

你可以使用 useHistory 钩子。检查这个:enter link description here 【参考方案1】:

使用这个:

onClick=()=>handleSelect(data.id)

并修改您的handleSelect 如下:

const handleSelect = (id) => 
    this.props.router.push(
      pathname: '/pathname',
      state: 
        id: id
      
    )
  ;

或使用useHistory:

const handleSelect = (id) => 
    history.push(pathname: '/YOUR PATH',
      state:   
        id: id, 
      ,)
  


对于您的编辑部分:

    导入 useHistory 并使用它:
import  useHistory  from "react-router-dom";

// in your component define a history variable
const history = useHistory();

// then use it whenever you want:
history.push(
  pathname: '/your path', //change the value to whatever you want
  state:   
    id: id, // you can add other variables as well
  ,
); 
    现在您可以在目标组件中访问此变量: 在类组件中:
this.props.location

在功能组件中:

import  useLocation  from 'react-router-dom';

const location = useLocation();
let id  = location.state.id;

【讨论】:

在第一种方法中,我在 id:Parameter 'id' implicitly has an 'any' type.ts(7006) 上得到一个错误:'this' implicitly has type 'any' because it does not have a type annotation.ts(2683) PlayersPage.tsx(11, 10): An outer value of 'this' is shadowed by this container. 第一种方法是类组件!如果你使用功能组件,你应该使用useHistory,你定义了useHistory吗?您应该按如下方式使用它:const history = useHistory(); 用历史记录方法好了,我得到了这些错误:Property 'push' does not exist on type 'History'.ts(2339)Cannot find name 'pathname'.ts(2304),和Cannot find name 'state'.ts(2304) 我编辑了我的问题以显示我在哪里。 我收到错误:Module '"react-router-dom"' has no exported member 'useHistory'.ts(2305) 我已经运行了 yarn install 和 yarn add @types/react-router-dom 但问题仍然存在【参考方案2】:

在您的handleSelect 方法中,您需要传递data.id 参数。

onClick=handleSelect(data.id)

并在您的处理程序中处理它。但是你必须像这样包装函数。

const handleSelect = (clickEvent) => (dataId) 
    //dataId will be available to use here
    navigate('../Player/');
;

然后我会看看 useHistory 钩子,因为历史道具被认为是遗留的。

import React from 'react';
import  useHistory  from 'react-router-dom';

const Hello = () => 
  const history = useHistory();
  const handleClick = () => history.push('/goodbye');

  return (
    <button type="button" onClick=handleClick>
      Goodbye
    </button>
  );
;

export default Hello;

因此,当您推送到历史 URL 时,您可以创建使用该参数的路由。像这样的:

history.push('/yourURL/:dataId');

然后在该页面上,您可以拉下该参数,您的应用可以使用它。

【讨论】:

使用onClick=handleSelect(data.id)不正确,应改为onClick=()=&gt;handleSelect(data.id)

以上是关于如何使用没有 <Link> 标签的 react-router-dom 发送参数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React-Router 的服务器端渲染中的 <Link> 标签更改 StaticRouter 的位置道具

自闭合标签-主动闭合标签-meta-link标签

如何在 Buefy 中使用 nuxt-link 标签?

html中link的用法

link and import

link标签的rel属性