使用react-router

时间:2016-05-18 13:26:00

标签: iframe reactjs react-router

我有一个多步骤表单,我使用react-router在不同步骤之间导航。 在部分步骤中,我向用户展示了iframe。 当用户在步骤之间导航时,它总是卸载并重新安装iframe,这会导致两个问题:

  1. 从源头重新加载iframe,使其跳转。
  2. 因为它是一个iframe,我无法控制其内部状态,并且它会失去步骤之间的状态。因此,如果用户对iframe有一些输入,则在移动到下一步时输入将丢失。
  3. 有没有办法将iframe实例保留在某个全局存储中,并且只在必要时才将其挂载到DOM?

    其他任何想法如何解决这个问题?

    感谢。

2 个答案:

答案 0 :(得分:5)

  

有没有办法将iframe实例保留在某个全局存储中   只在必要时将它挂载到DOM?

是的,你可以,但如果你甚至从DOM中删除iframe并在以后重新附加它仍然会重新加载,所以这样问题实际上与React的组件树几乎没什么关系。你真正需要的只是隐藏你的iframe并在以后再次显示它。

您当然可以隐藏并在React中显示iframe:

{ <iframe src="..." style={{display: this.state.showing ? "block" : "none"}} /> }

在这种情况下,您需要在 not 卸载的某个位置渲染iframe。您可以使用树中更下方的组件向上通信以显示/隐藏iframe。

但是,如果您真的希望能够隐藏/显示组件树中不同位置的iframe,可以安装和卸载,但是它会变得相当棘手而不是React的典型用例。

您需要自己创建DOM iframe,并将其附加到React组件树之外的DOM中(这通常是React中的反模式)。然后,您可以使用代理组件在安装和卸载时显示/隐藏此DOM元素。

这是一个将iframe附加到document.body并在安装组件时显示iframe并在卸载组件时隐藏它的示例:

class WebView extends React.Component {
  static views = {};
  componentDidMount() {
    if (!WebView.views[this.props.url]) {
      WebView.views[this.props.url] = this.createWebView(this.props.url);
    }
    WebView.views[this.props.url].style.display = "block";
  }
  componentWillUnmount() {
    WebView.views[this.props.url].style.display = "none";
  }
  createWebView(url) {
    let view = document.createElement("iframe");
    view.src = this.props.url;
    document.body.appendChild(view);
    return view;
  }
  render() {
    return null;
  }
}

Here it is working on CodePen:请注意,当您隐藏(卸载)然后显示(装载)WebView iframe状态(例如搜索输入)保持不变时。

您还需要对iframe的位置和大小进行正确显示。我没有表现出来,因为一般来说解决起来有点困难。

请注意,此解决方案类似于"portal" pattern。这里的区别是不要卸载iframe以保持其状态并防止重新加载。

答案 1 :(得分:2)

很简单,如果未渲染父级,则无法在渲染树中保留组件。也就是说,当路线发生变化时,如果您的组件是Route的子项,则必须卸载该组件。

侧面步骤的一种方法是使您的组件不是任何路径的孩子。通过这种方式,您将始终在每个路由中将此组件一起呈现。然后,您可以在适当的时候使用样式来显示/隐藏它。显然,这将部分地破坏DOM的结构。