Подтвердить что ты не робот

Реагировать только на модные маршруты маршрутизатора

У меня есть общедоступная и частная область в моем приложении, и я хочу показать диалог модальности входа в систему в общедоступном представлении. Модаль должен иметь свой собственный маршрут. Второй вариант использования - это модальный профиль в частной области.

Проблема заключается в том, что текущее представление в фоновом режиме исчезнет, ​​когда модальность будет показана, потому что модаль не является дочерним по отношению к текущему маршруту просмотров.

Так как я не хочу добавлять один и тот же модальный путь к любому возможному маршруту просмотра, вот вопрос: можно ли отделить модальные маршруты от своих родительских маршрутов и показать их везде в приложении без основного рендеринга содержимого? Каков наилучший подход для этого? Я нашел эту проблему, но, похоже, это не проблема.

Обновление браузера на модальном маршруте ничего не даст в фоновом режиме, но это проблема, с которой я мог бы жить.

4b9b3361

Ответ 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, если это необходимо.

Ответ 2

Использовать shouldComponentUpdate, это будет очень просто

<Router history={newHistory}>
        <Route path="/" component={App}>
          <Route path="home" component={Container} >
            <IndexRedirect to="home"/>
            <Route path="login" component={Authentication}/>
            <Route path="home" component={Home}/>
            <Route path="post/:id" component={Post}/>
          </Route>
        </Route>
</Router>


<Link to='/post/123' state={{isModal:true}}/>
<Link to='/home' state={{isModal:false}}/>
<Link to='/login' state={{isModal:true}}/>


Container = React.createClass({
  render() {
    let isModal = (location.state && location.state.modal);
      return (
        <div id="MeContainer">
          <ModalControlOpen isModal={isModal}>
            <Modal returnTo={this.props.location.pathname}>
              {this.props.children}
            </Modal>
          </ModalControlOpen>
          <ModalControlClose isModal={isModal}>
            {this.props.children}
          </ModalControlClose>
        </div>
      )
   
  }
});

ModalControlOpen = React.createClass({
  render(){
    if (this.props.isModal) {
      return (

        this.props.children
      )
    } else return <div></div>

  }
});

ModalControlClose = React.createClass({
  shouldComponentUpdate(nextProp){
    return !nextProp.isModal
  },
  render(){
    return (
      this.props.children
    )
  }
});