Ответ 1
Я думаю, что ваш лучший вариант, вероятно, заключается в использовании скрытых state
или строк запроса (для постоянных ссылок) или обоих, особенно если модальный (например, мода входа) может отображаться на любой странице. На всякий случай, если вы не знаете, React Router предоставляет state
часть API истории, что позволяет хранить данные в истории пользователей, которые на самом деле не отображаются в URL-адресе.
Вот набор маршрутов, которые я имею в виду; вы можете прыгать прямо в рабочий стол на JSBin, если хотите. Вы также можете просмотреть появившееся в результате приложение в своем собственном окне, чтобы вы могли видеть изменение URL-адресов (оно использует стратегию размещения хэша для совместимости с JSBin) и чтобы обновить работает так, как вы ожидали.
const router = (
<Router>
<Route component={LoginRedirect}>
<Route component={LocationDisplay}>
<Route path="/" component={ModalCheck}>
<Route path="/login" component={makeComponent("login")} />
<Route path="/one" component={makeComponent("one")} />
<Route path="/two" component={makeComponent("two")} />
<Route path="/users" component={makeComponent("users")}>
<Route path=":userId" component={UserProfileComponent} />
</Route>
</Route>
</Route>
</Route>
</Router>
);
Давайте исследовать эти маршруты и их компоненты.
Прежде всего, makeComponent
- это просто метод, который берет строку и создает компонент React, который отображает эту строку как заголовок, а затем все его дочерние элементы; это просто быстрый способ создания компонентов.
LoginRedirect
- это компонент с одной целью: проверьте, есть ли путь /login
или строка запроса ?login
на текущем пути. Если любое из них истинно, и текущее состояние не содержит ключа login
, оно устанавливает ключ login
в состоянии true
. Маршрут используется, если любой дочерний маршрут сопоставляется (то есть компонент всегда отображается).
class LoginRedirect extends React.Component {
componentWillMount() {
this.handleLoginRedirect(this.props);
}
componentWillReceiveProps(nextProps) {
this.handleLoginRedirect(nextProps);
}
handleLoginRedirect(props) {
const { location } = props;
const state = location.state || {};
const onLoginRoute = location.query.login || location.pathname === "/login";
const needsStateChange = onLoginRoute && !state.login;
if (needsStateChange) {
// we hit a URL with ?login in it
// replace state with the same URL but login modal state
props.history.setState({login: true});
}
}
render() {
return React.Children.only(this.props.children);
}
}
Если вы не хотите использовать строки запросов для показа модальности входа, вы можете, конечно, изменить этот компонент в соответствии с вашими потребностями.
Далее LocationDisplay
, но это только компонент, который я создал для демонстрации JSBin, которая отображает информацию о текущем пути, состоянии и запросе, а также отображает набор ссылок, демонстрирующих функциональность приложения.
Состояние входа важно для следующего компонента, ModalCheck
. Этот компонент отвечает за проверку текущего состояния для login
(или profile
или, возможно, любых других) ключей и отображение соответствующего модального файла, если это необходимо. (Демо JSBin реализует супер простой модальный, ваш, безусловно, будет приятнее.:) Он также показывает статус модальных проверок в текстовой форме на главной странице.)
class ModalCheck extends React.Component {
render() {
const location = this.props.location;
const state = location.state || {};
const showingLoginModal = state.login === true;
const showingProfileMoal = state.profile === true;
const loginModal = showingLoginModal && <Modal location={location} stateKey="login"><LoginModal /></Modal>;
const profileModal = showingProfileMoal && <Modal location={location} stateKey="profile"><ProfileModal /></Modal>;
return (
<div style={containerStyle}>
<strong>Modal state:</strong>
<ul>
<li>Login modal: {showingLoginModal ? "Yes" : "No"}</li>
<li>Profile modal: {showingProfileMoal ? "Yes" : "No"}</li>
</ul>
{loginModal}
{profileModal}
{this.props.children}
</div>
)
}
}
Все остальное является довольно стандартным материалом React Router. Единственное, что следует учитывать, это Link
внутри LocationDisplay
, которые показывают, как вы можете ссылаться на различные места в вашем приложении, показывая модальности при определенных обстоятельствах.
Прежде всего, вы можете, конечно, ссылку (и permalink) на любую страницу с просьбой показать модальности входа, используя ключ login
в строке запроса:
<Link to="/one" query={{login: 1}}>/one?login</Link>
<Link to="/two" query={{login: 1}}>/two?login</Link>
Вы также можете, конечно, напрямую ссылаться на URL /login
.
Затем обратите внимание, что вы можете явно указать состояние, чтобы модальное отображение, и это не изменит URL. Тем не менее, он будет сохраняться в истории, поэтому back/forward можно использовать так, как вы ожидали, и обновление отобразит модальную надпись на той же фоновой странице.
<Link to="/one" state={{login: true}}>/one with login state</Link>
<Link to="/two" state={{login: true}}>/two with login state</Link>
Вы также можете ссылаться на текущую страницу, добавляя особый модальный.
const path = props.location.pathname;
<Link to={path} state={{login: true}}>current path + login state</Link>
<Link to={path} state={{profile: true}}>current path + profile state</Link>
Конечно, в зависимости от того, как вы хотите, чтобы ваше приложение работало, не все это применимо или полезно. Например, если модальный действительно глобальный (то есть он может отображаться независимо от маршрута), это может работать нормально, но для модалов, например, для отображения профиля данного пользователя, я бы вероятно, сделайте это отдельным маршрутом, вложив его в родительский элемент, например:
<Route path="/users/:id" component={UserPage}>
<Route path="/users/:id/profile" component={UserProfile} />
</Route>
UserProfile
, в этом случае, будет компонентом, который делает модальным.
Другим примером, где вы можете внести изменения, является сохранение определенных модалов в истории; если вы этого не хотите, используйте replaceState
вместо setState
, если это необходимо.