#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>
);
}
}