如何使用 React 正确设置 react-router-dom 链接

How to set properly react-router-dom links with React

由于缺乏经验,我一直在为我的第一个个人项目而苦苦挣扎,这是我遇到的麻烦:

我需要设置一个 Link 组件(属于 react-router-dom),当我单击按钮时它会将我带到另一个新页面。认为我需要将选择传递给 link(和上下文)id,以便我可以从 API 获取数据,但我不知道如何让它工作。这是按钮 link 组件:

Model.jsx

import React, { useState, useContext } from 'react';
import { BrowserRouter as Router, Switch, Route, Link, Redirect } from 'react-router-dom';
import FileModel from "../FileModel/FileModel";
import { ModelsContext } from "../../context/ModelsContext";

const Model = ({modelo}) => {

    const { id, name, year, price, photo } = modelo;

    const { guardarModelo } = useContext(ModelsContext);

    const [display, setDisplay] = useState("btn-notdisplayed");
    const showButton = e => {
      e.preventDefault();
      setDisplay("btn-displayed");
    };
  
    const hideButton = e => {
      e.preventDefault();
      setDisplay("btn-notdisplayed");
    };

 

    return (   
            <div 
                className="card"
                onMouseEnter={e => showButton(e)}
                onMouseLeave={e => hideButton(e)}
            >
                <div className="card-body">
                    <p className="card-name">{name}</p>
                    <p className="card-yearprice">{year} | $ {price}</p>
                </div>
                <img src={`https://challenge.agenciaego.tech${photo}`} className="card-image" alt={`Imagen de ${name}`} />
                <Router>
                    <button 
                        type="button" 
                        className={display}
                        onClick={() => {
                            guardarModelo(modelo);
                        }}
                    ><Link to={`/models/${modelo.id}`}>Ver Modelo</Link>
                    </button>
                    <Switch>
                        <Route exact path={`/models/${modelo.id}`} component={FileModel} />
                    </Switch>
                </Router>         
            </div>   
     );
}
 
export default Model;

然后我从上下文中获取了数据:

ModelsContext.jsx

import React, { createContext, useState, useEffect } from 'react';

export const ModelsContext = createContext();

const ModelsProvider = (props) => {

        //State de modelos
        const [ modelo, guardarModelo ] = useState({});
        const [ modelos, guardarModelos ] = useState([]);
        const [ allModelos, guardarAllModelo ] = useState([]);
 

         //Cargar un modelo
         useEffect(() => {
             const consultarAPI = async () => {
                

                 const api = await fetch("https://challenge.agenciaego.tech/models");
                 const modelos = await api.json();

                 const api2 = await fetch(`https://challenge.agenciaego.tech/models/${id}`);
                 const modelo = await api2.json();
                 
                 guardarAllModelo(modelos);
                 guardarModelos(modelos);
                 guardarModelo(modelo);

             }
             consultarAPI()
         }, []);

    return (
        <ModelsContext.Provider
            value={{
                allModelos,
                modelo,
                modelos,
                guardarModelo,
                guardarModelos
            }}
        >
            {props.children}
        </ModelsContext.Provider>
    )
}

export default ModelsProvider;

最后,我得到了App.js,我从中路由了主要组件,我的想法是将Link作为一个名为“FileModel.jsx”的新组件子组件因此维护 Navbar 组件。

App.js

import React from "react";
import Navbar from "./components/Nav/Navbar";
import Models from "./components/Models/Models";
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Logo from "./assets/img/logo.png";
import ModelsProvider from "./context/ModelsContext";
import ModelFooter from "./components/Models/ModelFooter";

function App() {

  return (
    <ModelsProvider> 
        <Router>
            <nav className="navbar">
                <img src={Logo} className="logo" alt="Ego Logo" />
                <div className="menu-container">
                    <Link to={'/models'} className="menu-items">Modelos</Link>
                    <a className="menu-items">Ficha de modelo</a>
                </div>
                <div className="bottom-line"></div>
            </nav>
            <Switch>
              <Route exact path='/models' component={Models} />
            </Switch>
        </Router>
        <Navbar />
        <ModelFooter /> 
    </ModelsProvider>
  );
}

export default App;

这是目前的文件Model.jsx:

import React, { useContext } from 'react';
import Navbar from "../Nav/Navbar";
import { ModelsContext } from "../../context/ModelsContext";

const FileModel = () => {

    const { modelo } = useContext(ModelsContext);

    console.log(modelo.id);

    return ( 
        <Navbar />
     );
}
 
export default FileModel;

希望把我的问题解释清楚,非常感谢各位爱心人士!

干杯!

Ps:也许您可以找到一些需要重构的东西(稍后我需要检查我的代码),如果您找到类似的东西,我们将不胜感激!

更新

由于Linda的推荐,我将两个上下文合并为一个,并更改了我之前写的一些代码行,我无法设置状态将solo模型传递给fileModel组件,Link仍然不工作,我在想一个可以做到的功能,我做了另一个状态,一个单一的模型,但是当我点击按钮时我得到一个错误和未定义,因为 Idk 如何在状态中设置 Id 并传递它对于 API 调用,终端说 id in const api2 = await fetch(https://challenge.agenciaego.tech/models/${id});未定义。

我终于解决了我的问题!!!我不得不在我的组件之间重新定位一些元素,以使 api 上下文获取 id 并将其传递给 FileModel 组件,并将 Link 路由器更改为 App.js,这就是我的方式获取解决方案:

App.js

import React from "react";
import Navbar from "./components/Nav/Navbar";
import Models from "./components/Models/Models";
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Logo from "./assets/img/logo.png";
import ModelsProvider from "./context/ModelsContext";
import ModelFooter from "./components/Models/ModelFooter";
import FileModel from "./components/FileModel/FileModel";


function App() {

  return (
    <ModelsProvider> 
        <Router>
            <nav className="navbar">
                <img src={Logo} className="logo" alt="Ego Logo" />
                <div className="menu-container">
                    <Link to={'/models'} className="menu-items">Modelos</Link>
                    <Link to={`/models/1`} className="menu-items">Ficha del Modelo</Link>
                </div>
                <div className="bottom-line"></div>             
            </nav>
            <Switch>
              <Route exact path='/models' component={Models} />
              <Route exact path='/models' component={Models} />
            </Switch>
        </Router>
        <Navbar />
        <FileModel />
        <ModelFooter />
    </ModelsProvider>
  );
}

export default App;

Modelscontext.jsx

import React, { createContext, useState, useEffect } from 'react';

export const ModelsContext = createContext();

const ModelsProvider = (props) => {

        //State de modelos
        const [ modelo, guardarModelo ] = useState([]);
        const [ modelos, guardarModelos ] = useState([]);
        const [ allModelos, guardarAllModelo ] = useState([]);

        
        const { id } = modelo;

         //Cargar un modelo
         useEffect(() => {
             const consultarAPI = async () => {
                

                 const api = await fetch("https://challenge.agenciaego.tech/models");
                 const modelos = await api.json();

                 const api2 = await fetch(`https://challenge.agenciaego.tech/models/${id}`);
                 const modelo = await api2.json();
                 
                 guardarAllModelo(modelos);
                 guardarModelos(modelos);
                 guardarModelo(modelo);

             }
             consultarAPI()
         }, [modelo.id]);

    return (
        <ModelsContext.Provider
            value={{
                allModelos,
                modelo,
                modelos,
                guardarModelo,
                guardarModelos
            }}
        >
            {props.children}
        </ModelsContext.Provider>
    )
}

export default ModelsProvider;

Model.js

import React, { useState, useContext } from 'react';
import { Link } from 'react-router-dom';
import { ModelsContext } from "../../context/ModelsContext";


const Model = ({modelo}) => {

    const { name, year, price, photo } = modelo;

    const { guardarModelo } = useContext(ModelsContext);

    const [display, setDisplay] = useState("btn-notdisplayed");
    const showButton = e => {
      e.preventDefault();
      setDisplay("btn-displayed");
    };
  
    const hideButton = e => {
      e.preventDefault();
      setDisplay("btn-notdisplayed");
    };

    return (   
            <div 
                className="card"
                onMouseEnter={e => showButton(e)}
                onMouseLeave={e => hideButton(e)}
            >
                <div className="card-body">
                    <p className="card-name">{name}</p>
                    <p className="card-yearprice">{year} | $ {price}</p>
                </div>
                <img src={`https://challenge.agenciaego.tech${photo}`} className="card-image" alt={`Imagen de ${name}`} />
                    <Link to={`/models/${modelo.id}`}><button 
                        type="button" 
                        className={display}
                        onClick={() => {
                            guardarModelo(modelo);
                        }}
                    >Ver Modelo
                    </button></Link>
            </div>   
     );
}
 
export default Model;

文件Model.js(到目前为止...)

import React, { useContext } from 'react';
import Navbar from "../Nav/Navbar";
import { ModelsContext } from "../../context/ModelsContext";

const FileModel = () => {

    const { modelo } = useContext(ModelsContext);

    const { photo, name } = modelo;

    return (
        <> 
        <Navbar />
        <section>
            <img src={`https://challenge.agenciaego.tech${photo}`} alt={`Imagen de ${name}`}/>
        </section>
        </>
     );
}
 
export default FileModel;

感谢 Linda 给我重构上下文的输入!干杯!