使用 react-router 将组件保持在路由之间

IT技术 iframe reactjs react-router
2021-05-03 13:47:42

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

  1. 它从其源重新加载 iframe,使其跳转。
  2. 由于它是一个 iframe,我无法控制它的内部状态,并且它在步骤之间丢失了状态。因此,如果用户对 iframe 有一些输入,则在进行下一步时,输入会丢失。

有没有办法将 iframe 实例保存在某个全局存储中,并且仅在必要时将其挂载到 DOM 中?

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

谢谢。

2个回答

有没有办法将 iframe 实例保存在某个全局存储中,并且仅在必要时将其挂载到 DOM 中?

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

你当然可以像这样在 React 中隐藏和显示 iframe:

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

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


但是如果你真的希望能够在你的组件树中挂载和卸载的不同位置隐藏/显示 iframe ,你可以,但它变得有点棘手,而不是 React 的典型用例。

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

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

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

这是在 CodePen 上工作的:请注意,当您隐藏(卸载)然后显示(安装)时WebView,iframe 状态(例如搜索输入)保持不变。

您还需要定位和调整 iframe 的大小以正确显示在您的布局中。我没有展示这个,因为它一般有点难以解决。

请注意,此解决方案类似于“门户”模式这里的区别在于永远不要卸载 iframe 以保留其状态并防止重新加载。

很简单,如果未渲染父组件,则无法在渲染树中保留组件。也就是说,当路由更改时,如果您的组件是Route.

一种回避方法是让您的组件根本不是任何 Route 的子组件这样,您将始终每个 Route旁边渲染此组件然后您可以在适当的时候简单地使用样式来显示/隐藏它。显然,这会在一定程度上损害 DOM 的结构。