Как создать динамическую маршрутизацию, называющую маршруты на основе реквизитов компонента в react-router-dom

#reactjs #react-router #react-router-dom

#reactjs #react-маршрутизатор #react-router-dom

Вопрос:

Давайте представим, что у меня есть компонент, который отображает несколько divs подряд.

Это довольно просто

 if (props.hotels.length != undefined) {
    const data = props.hotels;
    const listItems = data.map((d) => (
      <div className="hotel-row">
        <Hotel name={d.name} category={d.category} image={d.image} description={d.description}/>
      </div>
    ));

    return <div className="hotel-list">{listItems}</div>;
  }
  

Приведенный выше код вернет список divs, содержащий содержимое Hotel, что довольно просто.

     import * as React from "react";
    
    const Hotel = (props) => {
      return <p>{props.name} {props.category} {props.image} {props.description}</p>
    };

export default Hotel
  

Теперь я хочу, чтобы при нажатии на каждый div он перенаправлял меня на новый маршрут.

Этот маршрут был бы

/hotel/{d.name}

Я думал о том, чтобы сделать что-то вроде этого

 <div className="hotel-row">
    <Hotel name={d.name} category={d.category} image={d.image} description={d.description} onClick={() => <Redirect to={"/" d.name} />}/>
</div>
  

И затем я хочу загрузить по этому маршруту остальную часть d.name во время монтирования компонента, чтобы я мог извлекать данные из api.

Мой маршрутизатор в настоящее время выглядит следующим образом

 import * as React from "react";
import { Route, Switch, withRouter, Redirect } from "react-router-dom";
import HotelList from "../Components/HotelList";
import Count from "../Components/Count";

const Router = () => {
    const renderFor404Routes = () => <Redirect to="/" />;
    return (
      <div>
        <Switch>
          <Route exactly component={HotelList} exact path="/" />
          <Route exactly component={Count} exact path="/count" />
          <Route path="/" exactly component={renderFor404Routes} />
        </Switch>
      </div>
    );
  };
  
  export default withRouter(Router);
  

Это также может показаться проблемой, поскольку, если я хочу перейти к маршруту, подобному

/hotel /name, и это имя не существует в моей базе данных, оно ничего не извлечет, и компонент выйдет из строя

Ответ №1:

То, о чем вы говорите, — это использование динамических маршрутов. Очень распространенная проблема, и ее не так уж сложно решить. Во-первых, я бы преобразовал ваш <Hotel> в <Link> , используя to реквизит:

     const Hotel = (props) => {
      return 
        <Link to={`/${props.name}`}>
          {props.name} {props.category} {props.image} {props.description}
        </Link>
    };
  

Теперь вам не нужен onClick => <Redirect /> , что очень неудобно. Link Сделает это за вас. Теперь вам нужно настроить компонент, который сможет обрабатывать динамически сгенерированный маршрут:

 // in your Switch statement:

<Route path="hotels/:hotelid" exactly component={HotelPage} />
  

Итак, теперь маршрутизация в /hotel/somehotelId будет отображать ваш HotelPage компонент. Конечно, внутри этого компонента вам нужно получить конкретный идентификатор, к которому вы направлялись. Который доступен как часть match реквизита:

 const HotelPage = ({ match }) => {

  const { hotelId } = match.location

  // now you can make any API calls related to that hotel id,
  // or render whatever you need based on that id

}
  

Это краткое изложение. Эта статья представляет собой более подробное объяснение тех же концепций.

Ответ №2:

React router dom позволяет достичь этого с помощью параметров пути, где вы можете указать маршрут, который будет иметь значение типа /hotel/:name , где name — это имя параметра пути.

Итак, к вашему <Switch> вы можете добавить другой путь, например

 <Route exact path="/hotel/:name" component={HotelByName}  />
  

Предполагая, что вы визуализируете компонент HotelByName , react-router-dom предоставляет значение для конкретных параметров пути с помощью useParams() перехвата, предоставляемого react-router-dom. После чего вы можете использовать его для API в вашем

например, для HotelByName (хуки)

 function HotelByName() {
  // We can use the `useParams` hook here to access
  // the dynamic pieces of the URL.
  let { name } = useParams();

  //or component did mount if class based
  useEffect(() => {
     //make API request with acquired name    
  }, [])

  return (
    <div>
      {/* Whatever hotel data you extract */}
    </div>
  );
}
  

для компонента на основе классов

 class HotelByName extends Component {

  componentDidMount = () => {
  let { name } = this.props.match.params;
  //make request with acquired name
}

  render () {
   return (
    <div>
      {/* Whatever hotel data you extract */}
    </div>
  );
 }
}