Использование MemoryRouter внутри BrowserRouter - PullRequest
2 голосов
/ 17 марта 2020

В моем проекте мне нужно переходить от одного компонента к другому без изменения URL. Для этого я использовал MemoryRouter, который работал как ожидалось. Но теперь одна и та же идея должна работать для разных маршрутов, т.е. /one и /two. Например,

/one --> BrowserRouter (url change visible)
    /
    /first
    /second
    /third
/two --> BrowserRouter (url change visible)
    /
    /first
    /second
    /third

Для новых видимых маршрутов, т. Е. /one и /two, уже установленных рабочих маршрутов памяти (т. Е. /, /first, /second, /third) должен корректно работать с соответствующими данными, как указано в /one и /two.

Я пытаюсь включить MemoryRoutes в BrowserRoutes со следующим структурным кодом:

    <BrowserRouter>
      <Switch>
        <Route path="/one" render={() => <MemoryComp configFor="Dave"></MemoryComp>}></Route>
        <Route path="/two" render={() => <MemoryComp configFor="Mike"></MemoryComp>}></Route>
      </Switch>
    </BrowserRouter>

и тогда MemoryComp содержит:

  <MemoryRouter history={customHistory}>
    <Switch>
      <Route path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
      <Route path="/first" component={FirstPage}></Route>
      <Route path="/second" component={SecondPage}></Route>
      <Route path="/third" component={ThirdPage}></Route>
    </Switch>
  </MemoryRouter>

Чего я пытаюсь достичь:

  • Чтобы заставить экраны работать с BrowserRouter -> конфигурация MemoryRouter.
  • Для передачи данных из маршрута памяти в другой маршрут памяти на основе основного маршрута браузера. ( Попытка использовать history для достижения того же )

Примечание. Скорее, лучше обрабатывать маршрутизацию в браузере с серверной маршрутизацией. Кроме того, это, кажется, может быть достигнуто с любым плагином реакции-степпера. Но пытаюсь понять, что я делаю не так, просто для учебы.

Вот весь свернутый код, доступный для Stackblitz ( не работает ):

import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import { BrowserRouter, MemoryRouter, Route, Switch } from 'react-router-dom';
import { createBrowserHistory } from "history";

const customHistory = createBrowserHistory();

class MemoryComp extends Component{
  render(){
    return(
      <MemoryRouter history={customHistory}>
        <Switch>
          <Route path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
          <Route path="/first" component={FirstPage}></Route>
          <Route path="/second" component={SecondPage}></Route>
          <Route path="/third" component={ThirdPage}></Route>
        </Switch>
      </MemoryRouter>
    );
  }
}

class InitPage extends Component{
  render(){
    return (
      <>
        <ul>
          <li onClick={() => this.navigateTo("/")}>Init</li>
          <li onClick={() => this.navigateTo("/first")}>First</li>
          <li onClick={() => this.navigateTo("/second")}>Second</li>
          <li onClick={() => this.navigateTo("/third")}>Third</li>
        </ul>
        <div>{this.props.configFor}</div>
      </>
    )
  }

  navigateTo(path){
    this.props.history.push(path, {
      data: {
        configFor: this.props.configFor
      }
    })
  }
}

class FirstPage extends Component{
  constructor(props){
    super(props);
    this.data = this.props.history.location.state.data;
  }
  render(){
    return (
      <>
        <ul>
          <li onClick={() => this.navigateTo("/")}>Init</li>
          <li onClick={() => this.navigateTo("/first")}>First</li>
          <li onClick={() => this.navigateTo("/second")}>Second</li>
          <li onClick={() => this.navigateTo("/third")}>Third</li>
        </ul>
        <div>first page</div>
      </>
    )
  }

  navigateTo(path){
    this.props.history.push(path, {
      data: {...this.data, ...{pageName: 'first'}}
    })
  }
}

class SecondPage extends Component{
  constructor(props){
    super(props);
    this.data = this.props.history.location.state.data;
  }
  render(){
    return (
      <>
        <ul>
          <li onClick={() => this.navigateTo("/")}>Init</li>
          <li onClick={() => this.navigateTo("/first")}>First</li>
          <li onClick={() => this.navigateTo("/second")}>Second</li>
          <li onClick={() => this.navigateTo("/third")}>Third</li>
        </ul>
        <div>second page</div>
      </>
    )
  }

  navigateTo(path){
    this.props.history.push(path, {
      data: {...this.data, ...{name: 'deducedValue'}}
    })
  }
}

class ThirdPage extends Component{
  constructor(props){
    super(props);
    this.data = this.props.history.location.state.data;
  }
  render(){
    return (
      <>
        <ul>
          <li onClick={() => this.navigateTo("/")}>Init</li>
          <li onClick={() => this.navigateTo("/first")}>First</li>
          <li onClick={() => this.navigateTo("/second")}>Second</li>
          <li onClick={() => this.navigateTo("/third")}>Third</li>
        </ul>
        <div>third page</div>
      </>
    )
  }

  navigateTo(path){
    this.props.history.push(path, {
      data: this.data
    })
  }
}

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React'
    };
  }

  render() {
    return (
      <div>
        <BrowserRouter>
          <Switch>
            <Route path="/one" render={() => <MemoryComp configFor="Dave"></MemoryComp>}></Route>
            <Route path="/two" render={() => <MemoryComp configFor="Mike"></MemoryComp>}></Route>
          </Switch>
        </BrowserRouter>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

1 Ответ

2 голосов
/ 21 марта 2020

Сначала я подумал, что что-то не так с Switch в сочетании с MemoryRouter, но после некоторой отладки я понял, что на самом деле он полностью независим.

Проблема, с которой вы столкнулись, заключается в том, что ваш базовый маршрут памяти требует быть exact, в противном случае все другие маршруты будут совпадать с тем, что будут возвращены один и первый ('/'). Просто добавьте exact к вашему базовому маршруту.

<MemoryRouter>
    <Switch>
      <Route exact path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
      <Route path="/first" component={FirstPage}></Route>
      <Route path="/second" component={SecondPage}></Route>
      <Route path="/third" component={ThirdPage}></Route>
    </Switch>
  </MemoryRouter>

Будьте осторожны, если у вас есть еще больше вложенных маршрутов, чтобы всегда добавлять точное значение к root, например, /first должно быть точным для этого работать правильно:

<Route exact path="/first" component={FirstPage}></Route>
<Route path="/first/nested-1" component={SecondPage}></Route>
<Route path="/first/nested-2" component={ThirdPage}></Route>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...