React router: новый компонент рендерится только в существующем представлении - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь переключаться между двумя страницами, но столкнулся с множеством проблем при обучении react router

В моем App.js есть основание, которое при переходе приведет меня к Cart при нажатии.

  render()  {
    return (
      <div>
        <button type="button" className="btn btn-primary Bottom-right " onClick={(e) => this.handleSubmit(e)}>
              Confirmed Order
        </button>
        <button type="button" className="btn btn-Primary">
          <Link to="/displayCart" >Show Car</Link>
        </button>
      </div>
    );
  }
}

export default App;

В моем компоненте корзины также есть аналогичная кнопка, которая возвращает меня к компоненту App.

class Cart extends React.Component {
    constructor(props){
        super(props)

        this.state={
            cartData:null
        }
    }

    componentDidMount() {
        this.callApi()
          .then(res => this.setState({ cartData: res.express}))
          .catch(err => console.log(err));
      }

      callApi = async () => {
          const response = await fetch('/myCart');
          const body = await response.json();
          if (response.status !== 200) throw Error(body.message);

          return body;
      };

    render(){
        return(
            <div className="col">
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">Welcome to Shopping Center</h1>
                </header>
            </div>
                <div>{ReactHtmlParser(this.state.cartData)}</div>
                <button type="button Bottom-right" className="btn btn-Primary">
                    <Link to="/" >Keep Shopping</Link>
                </button>
            </div>
        )
    }
}

Мой index.js содержит два компонента, приложение JS являетсяКомпонент по умолчанию.

    ReactDOM.render(
        <BrowserRouter>
            <switch>
                <div>
                    <Route exact path="/displayCart" component={Cart}/>
                    <Route component={App} />
                </div>
            </switch>
        </BrowserRouter>,
        document.getElementById('root')
    );

Теперь они действительно имеют недостатки во многих уровнях:

1: Когда я щелкаю «Показать корзину» вместо рендеринга нового представления.Компонент корзины отображается в верхней части окна, а приложение по-прежнему отображается.

2: После нажатия кнопки «Показать корзину» я щелкнул «Показать приложение», чтобы вернуться к компоненту приложения, однако консоль выдает:

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in Cart (created by Route)

3: Если я изменил состояние в компоненте App при возврате к компоненту App из корзины component, состояние не обновлялось.Например (например, логическое значение «покупка» в товарах.) Когда я возвращаюсь из компонента приложения из корзины, состояние остается истинным, вместо этого я хочу, чтобы оно вернулось в исходное состояние.

Я следовал за учебником, но он просто сломан.Что я сделал не так

1 Ответ

0 голосов
/ 28 сентября 2018

Таким образом, предупреждение заключается в том, что setState вызывается <Cart /> даже после того, как вы вернетесь в приложение, что означает, что компонент корзины будет отключен к тому времени.

Вы должны следить за тем, когда Cart отключается.

Это можно сделать, создав переменную в своем компоненте Cart, например _isMounted, а затем используя событие жизненного цикла componentWillUnmount, чтобы отслеживать.

componentWillUnmount(){
   _isMounted =false
}

Затем, перед тем, как использовать setState, выполните быструю проверку, чтобы убедиться, что _isMounted истинно.

this.callApi()
          .then(res => if(isMounted){
                         this.setState({ cartData: res.express}))
                       }
          .catch(err => console.log(err));

Очевидно, вам также нужно изменить _isMounted на true, используяComponentDidMount

Вот статья на эту тему


Что касается состояния приложения, которое не «обновляется» ... это потому, что компонент приложения никогда неразмонтирует и монтирует снова, когда вы идете из App> Cart> App.

Чтобы исправить это, скажите switch, чтобы монтировать компонент <App /> только тогда, когда url-адрес точно соответствует домашней странице, используя exact path="/"

        <switch>
            <div>
                <Route exact path="/displayCart" component={Cart}/>
                <Route exact path="/" component={App} />
            </div>
        </switch>

Теперь, если вы хотите отслеживать изменения состояния, даже если оно закрыто (размонтировано) до завершения вызова API, вы должны создать внутри <App/> функцию, которая выполняет setState для вас и передайте его в качестве реквизита <Cart />, а затем изнутри Вы можете вызвать эту функцию реквизита.

Это будет работать, только если вы поместите свой React Router внутри

Я делаю это так: - index.js всегда загружается - Внутри я тогдаперенаправить на шоу правильный компонент

Это означает, что всегда монтируется.Тем не менее, он позволяет мне использовать состояние приложения как «основное» состояние по умолчанию, которое всегда существует, поскольку я никогда не отключаю его.Поэтому, если у меня есть дочерний компонент, такой как ..., я могу дать Cart одну из функций.Эта функция изменит состояние внутри независимо от того, установлен ли он / отображается.

Если вы реструктурируете свое приложение таким образом, вы можете сделать следующее:

App.js Добавьте функцию, которая изменит свое состояние.

changeState(key, value){
   this.setState({
      key : value
   }
}

Теперь передайте эту функцию как опору

    <BrowserRouter>
        <switch>
            <div>
                <Route exact 
                       path="/displayCart" 
                       render={
                         (props) => <Cart {...props} 
                         changeStateinApp={this.changeState} /> 
                       }
                  />
                <Route component={App} />
            </div>
        </switch>
    </BrowserRouter>,

Cart.js Теперь вызовите эту функцию

this.callApi()
          .then(res => 
              this.props.changeStateinApp(cartData, res.express)
          .catch(err => console.log(err));
...