Keep components between routes using react-router

后端 未结 2 508
Happy的楠姐
Happy的楠姐 2021-01-05 17:57

I have a multi-steps form and I\'m using react-router to navigate between the different steps. In some of the steps I show an iframe to the user. When the u

相关标签:
2条回答
  • Is there any way to keep the iframe instance in some global store and only mount it to the DOM when necessary ?

    Yes, you could, but if you even remove an iframe from the DOM and re-append it later it still gets reloaded, so in that way the problem actually has very little to do with React's component tree. What you really need is to just hide your iframe and show it again later.

    You could of course hide and show the iframe in React like this:

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

    In this case you need to render the iframe at some place that does not get unmounted. You can use components further down in your tree to communicate back upwards to show/hide the iframe.


    But if you really want to be able to hide/show the iframe from different places in your component tree that get mounted and unmounted, you can, but it gets quite a bit trickier and not a typical use-case of React.

    You'll need to create the DOM iframe yourself and append it somewhere into the DOM that is outside React's component tree (this is generally an anti-pattern in React). Then you can use a proxy component to show/hide this DOM element when mounted and unmounted.

    Here's an example that appends an iframe to the document.body and shows it when a component is mounted, and hides it when the component is unmounted:

    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: notice that when you hide (unmount) then show (mount) the WebView the iframe state (for example search input) stays the same.

    You will also need to position and size the iframe to appear within your layout correctly. I haven't shown this because it's a bit difficult to solve generally.

    Note that this solution is similar to the "portal" pattern. The difference here is to not ever unmount the iframe in order to preserve its state and prevent reloading.

    0 讨论(0)
  • 2021-01-05 18:16

    Quite simply, there's no way to preserve a component in the render tree if the parent is not rendered. That is, when the route changes, your component will necessarily be unmounted if it's a child to a Route.

    One way to side-step that is to make your component not a child to any Route at all. This way, you would always render this component alongside every Route. Then you can simply use styles to show/hide it when appropriate. Obviously, this will partly compromise the structure of your DOM.

    0 讨论(0)
提交回复
热议问题