【问题标题】:How to unmount a component on route change如何在路由更改时卸载组件
【发布时间】:2016-01-02 20:12:59
【问题描述】:

我在给定路线上有一个组件,比如app.com/cars/1

我有一个侧边栏,其中包含指向不同汽车的链接,例如 /cars/2/cars/3 等。

我遇到的问题是,当您更改链接时,例如从 cars/1 转到 cars/2,组件没有卸载,我得到 componentWillReceiveProps 被解雇。如果我转到具有不同组件的另一个页面,例如/trucks,则该组件已卸载并且一切正常。

当路由改变时如何卸载我的组件?我有各种状态和通量的东西,我想为下一辆车清除。或者如果不卸载,人们是否有处理这类问题的典型方式?我无法想象这不是很常见。

(注意我使用的是 react-router)

【问题讨论】:

    标签: javascript reactjs react-router react-router-dom


    【解决方案1】:

    我认为处理此问题的正常方法只是在componentWillReceiveProps 中取消注册和重新注册您的侦听器、重置您的状态等等。围绕这种行为创建抽象是正常的:

    componentWillMount: function() {
      this.setupStuff(this.props);
    }
    
    componentWillUnmount: function() {
      this.tearDownStuff();
    }
    
    componentWillReceiveProps: function(nextProps) {
      this.tearDownStuff();
      this.setupStuff(nextProps);
    }
    
    setupStuff: function(props) {
      this.setState(this.getDataFromStore(props.store));
      props.store.listen(this.handler); // or whatever
    }
    
    tearDownStuff: function(props) {
      props.store.unlisten(this.handler); // or whatever
    }
    

    但是,如果您真的想重新安装组件,可以使用几个选项。

    如果您不希望任何组件在路由更改时保持挂载,您可以利用路由器的the createElement option 为组件添加唯一键:

    function createElement(Component, props) {
      var key = ...; // some key that changes across route changes
      return <Component key={key} {...props} />;
    }
    
    // ...
    
    <Router createElement={createElement}>
      ...
    

    但是,我不建议这样做。它不仅使您的应用程序变慢,因为 每个 路由组件每次都在重新安装,而且它还完全禁用了诸如具有不同 props 的同一路由处理程序的后续渲染之间的动画之类的东西。

    如果您只希望某些 路由始终重新渲染,您可以通过React.cloneElement 在父级中为其提供一个键:

    render: function() {
      var key = ...; // some key that changes across route changes
      return React.cloneElement(
        React.Children.only(this.props.children),
        {key: key}
      );
    }
    

    【讨论】:

    • 现在仍然相关,但是,如果您的状态来自您无法控制的钩子,则重置状态并不容易。
    • @cdosborn 是的。我想我可能会将钩子用法包装在一个子组件中,并根据需要根据来自包装组件的一些其他数据使用不断变化的key 道具来渲染它,以启用强制重新挂载。见reactjs.org/blog/2018/06/07/…
    【解决方案2】:

    我最终只是做了:

    const createElement = (Component, props) =>
      <Component key={props.params.id} {...props}/>;
    
    ReactDOM.render(
      <Router history={browserHistory} createElement={createElement}>
        <Route path="courses/:id" component={Page_courses_id}/>
      </Router>
    );
    

    并忽略潜在的性能问题(如果它们发生的话),在我看来维护成本(重置 :dynamic-segment 下所有组件的状态、重新获取 componentWillReceiveProps 中的数据等)是不值得的。

    【讨论】:

    • 我有一些类似的情况...一个可以在左右打开和关闭的侧边栏我有 dhtmlx-scheduler 组件。在页面重新加载时一切正常,但是当我去 Route3 来时回到Route2,侧边栏和dhtmlx-cheduler都存在,然后打开侧边栏,调度器组件应该根据侧边栏展开时左侧的宽度调整其宽度,但调度器的一部分被切断。在页面上硬刷新,虽然它工作正常,并且在侧边栏展开时完美调整其宽度。我是否应该在每次路由更改时卸载调度程序组件。
    • 请找到附加的github链接github.com/sonalk215/dhtml任何指针都会非常有用
    • @sk215,我相信你会更幸运地提交这个问题。
    • 我提出了一个新问题,感谢湖人的建议 问题链接stackoverflow.com/questions/64563819/…
    【解决方案3】:

    我选择了带有更改键的 Michelle Tilley 选项,但我没有为路由器中的整个组件设置密钥,而只是为我需要通过重新启动挂钩来更新的那个组件。

    这很好用。

    const UniqComponent = () => {
      const uniqId = 123; // may be carId
      return <div key={uniqId} />
    }
    
    ReactDOM.render(
      <Router history={browserHistory}>
        <Route path="cars/:id" component={UniqComponent}/>
      </Router>
    );

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-10
      • 2019-06-14
      • 1970-01-01
      • 2017-03-06
      • 2018-02-24
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      相关资源
      最近更新 更多