Store components between routes using a react router

I have a multi-stage form and I use an interactive router to move between the various steps. In some steps, I show the iframe to the user. When the user moves between steps, he always unmounts and re-mounts the iframe, this causes two problems:

  • It reloads the iframe from its source, which makes it jump.
  • Since this is an iframe, I cannot control its internal state, and it loses state between steps. Therefore, if the user had some inputs in the iframe, the entries are lost when moving to the next step.

Is there a way to save the iframe instance in some global repository and only connect it to the DOM if necessary?

Any other ideas how to solve this problem?

Thanks.

+5
source share
2 answers

Is there a way to save an iframe instance in some kind of global storage and only mount it in the DOM if necessary?

Yes, you could, but if you even remove the iframe from the DOM and re-add it later, it will still restart, so the problem is actually very little related to the React component tree. You really need to just hide your iframe and show it later.

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

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

In this case, you need to display the iframe in some place that will not be unmounted. You can use the components further in your tree to talk back to show / hide the iframe.


But if you really want to hide / show the iframe from different places in the component tree that are mounted and unmounted, you can, but it becomes quite complex, not a typical React use case.

You will need to create the iframe DOM yourself and add it somewhere in the DOM, which is outside the React component tree (this is usually an anti-pattern in React). Then you can use the proxy component to show / hide this DOM element during installation and unmounting.

Here is an example that adds an iframe to document.body and shows it when the 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 works with CodePen : note that when you hide (disable), then show (mount) the WebView iframe state (for example, the search input) remains the same.

You will also need to place and resize the iframe to display correctly in your layout. I did not show this because it is a little difficult to solve as a whole.

Note that this solution is similar to the portal pattern. The difference here is to never unmount the iframe in order to maintain its state and prevent a reboot.

+4
source

Simply put, there is no way to save a component in the render tree if the parent is not displayed. That is, when the route changes, your component will be unmounted if it has a Route child.

One way to take a step so that your component is not a child of any Route at all. Thus, you always display this component along with each Route. Then you can simply use styles to show / hide it when necessary. Obviously, this will partially compromise the structure of your DOM.

+1
source

All Articles