Как правильно установить ссылки react-router-dom с помощью React

Я боролся со своим первым сольным проектом из-за отсутствия опыта, вот какая у меня проблема:

Мне нужно установить компонент Link (из react-router-dom), который переводит меня на другую новую страницу, когда я нажимаю кнопку. Думал, что при выборе мне нужно передать ссылку (и контекст) идентификатор, чтобы я мог получить данные из API, но я не могу понять, как заставить его работать. Это компонент ссылки кнопки:

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, из которого я маршрутизирую основной компонент. Идея состоит в том, чтобы получить ссылку на новый компонент с именем 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: Может быть, вы сможете найти некоторые вещи для рефакторинга (позже мне нужно будет проверить мой код). Если вы найдете что-то подобное, любая помощь будет оценена по достоинству!

ОБНОВЛЕНИЕ

По рекомендации Линды я объединил два контекста в один и изменил некоторые строки кода, который я написал ранее, я не могу установить состояние для передачи одиночной модели компоненту fileModel, а ссылка все еще не работает, я думал в функциях что это можно сделать, я сделал другое состояние, одиночное modelo, но когда я нажимаю кнопку, я получаю ошибку и undefined, потому что Idk, как установить в состоянии Id и, таким образом, передать его вызову API, терминал говорит, что идентификатор в константе api2 = ожидание выборки (https://challenge.agenciaego.tech/models/${id}); не определено.


person patricio1984    schedule 05.02.2021    source источник
comment
Я действительно не знаю, о чем вы спрашиваете. Можете ли вы поделиться ссылкой на CodeSandbox и объяснить, какая часть не работает? Вам не нужна эта вторая декларация Router внутри Model. Кроме того, я не совсем уверен, на что похожа навигация. Похоже, вы пытаетесь использовать один и тот же компонент как для миниатюры модели, так и для страницы одной модели. Вы не хотите этого. Вы можете делиться многократно используемыми частями, но вы хотите, чтобы их обертывали разными компонентами.   -  person Linda Paiste    schedule 06.02.2021
comment
Итак, это примерное представление о том, что мне нужно сделать, я делюсь двумя фотографиями по этой ссылке. Когда вы нажимаете черную кнопку Ver modelos, она должна ссылаться на новый компонент, где вы должны получить подробную информацию об автомобиле в новом компоненте, который должен отображаться в теге Ficha del modelo nav. photos   -  person patricio1984    schedule 06.02.2021
comment
Я попытался получить доступ к данным API, добавив информацию об идентификаторе кнопки через контекст, но я очень запутался в этой реализации маршрутизации конечных точек.   -  person patricio1984    schedule 06.02.2021
comment
Я обновил часть кода с вашими рекомендациями, Линда (в основном слияние двух контекстов), попробуйте немного, но все еще не работает перенаправление, idk, где разместить маршрутизатор в другом месте, которое могло бы работать.   -  person patricio1984    schedule 06.02.2021


Ответы (1)


НАКОНЕЦ-ТО Я РЕШИЛ СВОЮ ПРОБЛЕМУ!!! Мне пришлось перераспределить некоторые элементы между моим компонентом, чтобы контекст API взял идентификатор и передал его компоненту 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;

FileModel.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;

Спасибо Линде за помощь в рефакторинге контекста! ваше здоровье!

person patricio1984    schedule 06.02.2021