【问题标题】:Prevent component be unmounted with React-router防止组件被 React-router 卸载
【发布时间】:2015-10-30 08:09:49
【问题描述】:

当谈到 React-Router 组件时,我很笨拙。但是,当我浏览链接时,我无法找到解释为什么我的组件会被卸载?以及如何预防?

在我的示例中,我有一个包含计时器并通过

重新呈现内容的组件

我遇到了一个错误:

这是 ReactJS 代码:

/*global define, Backbone, React, $, Request, Router, Route, Link */

var App = React.createClass({
    render: function () {
        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/timer">Timer</Link></li>
                </ul>
                {this.props.children}
            </div>
        )
    }
});

var About = React.createClass({
    render: function () {
        return <h3>Here is about page</h3>
    }
});

var Timer = React.createClass({
    getInitialState: function() {
        return {counter: 0};
    },
    render: function () {
        return (
            <div>
                <h2>Time is running over...</h2>
                <b>{this.props.interval}</b>
                <p>{this.state.counter}</p>
            </div>
        )
    },
    componentDidMount: function () {
        this.loadCommentsFromServer();
        setInterval(this.loadCommentsFromServer, 1000);
    },
    loadCommentsFromServer: function () {
        this.setState({counter: this.state.counter + 1});
    }
});

React.render((
    <Router location="history">
        <Route path="/" component={App}>
            <Route path="about" component={About} />
            <Route path="timer" component={Timer} />
        </Route>
    </Router>
), document.body);

【问题讨论】:

  • 您希望计时器在整个应用程序中都处于活动状态吗?为什么你有它的具体路线?
  • 这只是一个例子。我的主要目标是在浏览链接期间不要卸载组件。在我的真实项目中,我有一个带有巨大网格的复杂组件。所以每次我回到这个组件时,它都会向服务器发送请求以获取数据。但我不需要这样的行为。而且我不明白为什么 React-Router 销毁组件而不是隐藏它?
  • 在这种情况下,react-router 的行为符合预期 - 如果您有一个不应卸载的组件,那么您需要将其组合到您的顶级应用程序组件中 - 请参阅下面的答案

标签: reactjs react-router


【解决方案1】:

如果您想再次显示组件而不卸载,您可以始终显示它并在路线离开时隐藏。 为了达到这个位置,您可以胜任外部目标路线,例如,您要阻止 ProjectsList 退出:

   <Route path="/" component={App}>
        <IndexRoute component={ProjectsList} />
        .....

1。将ProjectsList 放入App 并创建这样的代理组件而不是component={ProjectsList}

  const LayoutToogler = () => (<div></div>);

看起来会这样:

    <Route path="/(mobile.html)" component={App}>
        <IndexRoute component={LayoutToogler} showProjects={true}/>
  1. 在顶级 App 组件中,只需检查此属性 (showProjects) 即可决定是否显示项目:

           <ProjectsList
             style={{display:this.props.children.props.route.showProjects?'block':'none'}}
                    />
    

不要忘记在 ProjectList 组件中处理 style 属性

【讨论】:

    【解决方案2】:

    在您的情况下,react-router 正在按预期工作,如果您希望计时器在整个应用程序中可见,那么您需要将其视为组件而不是视图

    /*global define, Backbone, React, $, Request, Router, Route, Link */
    
    var App = React.createClass({
        render: function () {
            return (
                <div>
                    <h1>App</h1>
                    // this will not unmount when routes are changed
                    <Timer /> 
                    <ul>
                        <li><Link to="/about">About</Link></li>
                    </ul>
                    // this will unmount/mount when routes are changed
                    {this.props.children}
                </div>
            )
        }
    });
    
    var About = React.createClass({
        render: function () {
            return <h3>Here is about page</h3>
        }
    });
    
    var Timer = React.createClass({
        getInitialState: function() {
            return {counter: 0};
        },
        render: function () {
            return (
                <div>
                    <h2>Time is running over...</h2>
                    <b>{this.props.interval}</b>
                    <p>{this.state.counter}</p>
                </div>
            )
        },
        componentDidMount: function () {
            this.loadCommentsFromServer();
            setInterval(this.loadCommentsFromServer, 1000);
        },
        loadCommentsFromServer: function () {
            this.setState({counter: this.state.counter + 1});
        }
    });
    
    React.render((
        <Router location="history">
            <Route path="/" component={App}>
                <Route path="about" component={About} />
            </Route>
        </Router>
    ), document.body);
    

    【讨论】:

    • 但在这种情况下,计时器将始终可见。正如我之前在我的真实项目中提到的,我有一个带有巨大网格的复杂组件。所以每次我回到这个组件时,它都会向服务器发送请求以获取数据。但我不需要这样的行为。而且我不明白为什么 React-Router 会破坏组件而不是隐藏它?好像我不明白使用 react-router 的目的:(
    • @AlexeiBerkov 你有没有找到解决方案?
    • 我使用简单的 CSS 方法
    【解决方案3】:

    为避免在路由器再次挂载您的组件时获取/构造大/慢数据块,您可以这样做:1) 实现一个全局缓存对象(只需从应用的根目录导出一个空对象在纯javascript级别)2)在你的组件中,做:

    import {cache} from '.....App';
    const myComponent = props => {
    if (!cache.myBigList) {
      cache.myBigList = [];
    }
    const [list, setList] = useState(cache.myBigList);
    cache.myBigList = list;
    ...
    

    这样,第一次挂载组件时,它将在 [] 处启动缓存。 然后每次更改列表时再次执行该函数并将列表保存在缓存中。 当组件再次挂载时,给 useState 的初始状态是上次挂载周期最后保存的状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 2016-01-14
      • 2015-11-14
      • 1970-01-01
      相关资源
      最近更新 更多