React 路由器:新组件仅在现有视图上呈现

React router: new component only render on existing view

我正在尝试在两个页面之间切换,但是 运行 在学习过程中遇到很多问题 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 包含两个组件,app JS 是默认组件。

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

现在他们在很多层面上确实存在缺陷:

1:当我点击显示购物车时,而不是呈现新视图。购物车组件呈现在视图的顶部,App 仍然呈现。

2:单击 Show Cart 后,我​​单击 Show App 返回到我的 App Component,但是控制台打印:

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 组件中更改了状态,当我从购物车 component 返回到 App 组件时,状态没有得到刷新。例如(例如,项目中的布尔值 "purchase"。)当我从购物车的 App 组件返回时,状态保持为真,相反,我希望它回到初始状态。

我按照教程进行操作,但它只是坏了。我做错了什么

所以警告是因为 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));

显然您还需要使用 ComponentDidMount

_isMounted 更改为 true

这是一个article on this topic


关于应用程序的状态不是 'refreshing'...这是因为当您从应用程序 > 购物车 > 应用程序进入时,应用程序组件永远不会卸载和再次安装。

要解决此问题,请使用 exact path="/"

告诉 switch 仅在 url 与主页完全匹配时安装 <App /> 组件
        <switch>
            <div>
                <Route exact path="/displayCart" component={Cart}/>
                <Route exact path="/" component={App} />
            </div>
        </switch>

现在,如果您想跟踪状态变化,即使在 API 调用完成之前已关闭(卸载),那么您应该在 <App/> 中创建一个函数来执行 setState 并将其作为道具传递给 <Cart /> 然后从内部您可以调用此道具功能。

这只有在你将 React Router 的东西放在

中时才有效

我的做法是这样的: - index.js 始终加载 - 然后在我内部重定向到显示正确的组件

这意味着始终挂载。但是,它让我可以使用 App 的状态作为默认 "main" 状态,该状态始终存在,因为我从未卸载过它。因此,如果我有一个子组件,例如...,我可以为 Cart 提供其中一个功能。这个函数会改变里面的状态不管是否还是mounted/shown.

如果您像那样重组您的应用程序,那么您可以执行以下操作:

App.js 添加一个函数来改变它的状态。

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

现在将此函数作为 prop 传递

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