Preventing iframe reload upon page change on react

huangapple go评论72阅读模式
英文:

Preventing iframe reload upon page change on react

问题

I'm working on a simple react UI which uses react-router-dom for handling the pages and loads some iframes.
At the moment everything works, but, everytime a user navigate back and forth a page containing an iframe, it gets rerendered. My goal is to avoid that and let the users see the iframe as it was before switching pages.

To be more clear, follow these steps:

  • click on "Page with iframe"
  • The home of wikipedia is shown into the iframe
  • scroll or navigate to some random page into wikipedia's iframe
  • click on "Page with content"
  • click on "Page with iframe"

Current behavior: The iframe is reloaded and wikipedia's home is shown again

Desired behavior: The iframe is shown exactly as it was left before leaving the page

I've created this small react example in a sandbox: Link to Sandbox

Here is the code for reference:

import React, { useEffect, useState } from "react";
import { BrowserRouter as Router, Route, Routes, Link } from "react-router-dom";

function delay(time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

const fakeApi = async () => {
  await delay(1000);
  return {
    src: "https://fr.wikipedia.org/wiki/Main_Page"
  };
};

const Page1 = () => <div>Page with sample content</div>;

const Page2 = () => {
  const [iframeUrl, setIframeUrl] = useState(null);

  const loadIframe = async () => {
    const { src } = await fakeApi();
    setIframeUrl(src);
  };

  useEffect(() => {
    loadIframe();
  }, []);

  return (
    <div>
      <h3>Page with sample iframe</h3>
      <p>
        Every time a user moves to this page, the iframe is reloaded (e.g., if you try to scroll, navigate to "Page with content" and back to "Page with iframe," you'll see a new iframe is loaded).
      </p>
      <iframe src={iframeUrl} width="640" height="480" title="test wikipedia" />
    </div>
  );
};

export default () => (
  <Router>
    <ul>
      <li>
        <Link to="/contentpage">Page with content</Link>
      </li>
      <li>
        <Link to="/iframepage">Page with iframe</Link>
      </li>
    </ul>

    <hr />
    <Routes>
      <Route exact path="/contentpage" element={<Page1 />} />
      <Route path="/iframepage" element={<Page2 />} />
    </Routes>
  </Router>
);
英文:

I'm working on a simple react UI which uses react-router-dom for handling the pages and loads some iframes.
At the moment everything works, but, everytime a user navigate back and forth a page containing and iframe, it gets rerendered. My goal is to avoid that and let the users see the iframe as it was before switching pages.

To be more clear, follow these steps:

  • click on "Page with iframe"
  • The home of wikipedia is shown into the iframe
  • scroll or navigate to some random page into wikipedia's iframe
  • click on "Page with content"
  • click on "Page with iframe"

Current behavior: The iframe is reloaded and wikipedia's home is shown again

Desired behavior: The iframe is shown exactly as it was left before leaving the page

I've created this small react example in a sandbox: https://codesandbox.io/s/eloquent-cache-2s9ddn?file=/src/App.js

Here is the code for reference:

import React, { useEffect, useState } from &quot;react&quot;;
import { BrowserRouter as Router, Route, Routes, Link } from &quot;react-router-dom&quot;;
function delay(time) {
return new Promise((resolve) =&gt; setTimeout(resolve, time));
}
const fakeApi = async () =&gt; {
await delay(1000);
return {
src: &quot;https://fr.wikipedia.org/wiki/Main_Page&quot;
};
};
const Page1 = () =&gt; &lt;div&gt;Page with sample content&lt;/div&gt;;
const Page2 = () =&gt; {
const [iframeUrl, setIframeUrl] = useState(null);
const loadIframe = async () =&gt; {
const { src } = await fakeApi();
setIframeUrl(src);
};
useEffect(() =&gt; {
loadIframe();
}, []);
return (
&lt;div&gt;
&lt;h3&gt;Page with sample iframe&lt;/h3&gt;
&lt;p&gt;
Eveytime a users moves to this page the iframe is reloaded (ex. if you
try to scroll, navigate to &quot;Page with content&quot; and back to &quot;Page with
iframe&quot;, you&#39;ll see a new iframe is loaded)
&lt;/p&gt;
&lt;iframe src={iframeUrl} width=&quot;640&quot; height=&quot;480&quot; title=&quot;test wikipedia&quot; /&gt;
&lt;/div&gt;
);
};
export default () =&gt; (
&lt;Router&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;Link to=&quot;/contentpage&quot;&gt;Page with content&lt;/Link&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;Link to=&quot;/iframepage&quot;&gt;Page with iframe&lt;/Link&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;Routes&gt;
&lt;Route exact path=&quot;/contentpage&quot; element={&lt;Page1 /&gt;} /&gt;
&lt;Route path=&quot;/iframepage&quot; element={&lt;Page2 /&gt;} /&gt;
&lt;/Routes&gt;
&lt;/Router&gt;
);

答案1

得分: 1

我找到了一个解决方案,基本上我需要从react-router-dom库中提取页面并手动路由。

这有点像一个hacky修复,但考虑到整个用户界面的速度和可用性方面的巨大改进,我愿意接受这些妥协。

这是一个可工作的示例:https://codesandbox.io/s/optimistic-rgb-mmqyss?file=/src/App.js

以防万一它会停用,而某人仍然需要这个解决方案,这是代码:

import React, { useEffect, useState } from "react";
import {
  BrowserRouter as Router,
  Route,
  Routes,
  Link,
  useLocation
} from "react-router-dom";

function delay(time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

const fakeApi = async () => {
  await delay(1000);
  return {
    src: "https://fr.wikipedia.org/wiki/Main_Page"
  };
};

const Page1 = () => <div>Page with sample content</div>;

const Page2 = () => {
  const [iframeUrl, setIframeUrl] = useState(null);

  const loadIframe = async () => {
    const { src } = await fakeApi();
    setIframeUrl(src);
  };

  useEffect(() => {
    loadIframe();
  }, []);

  return (
    <div>
      <h3>Page with sample iframe</h3>
      <p>
        每次用户转到此页面时都会重新加载iframe例如如果您尝试滚动导航到带内容的页面然后返回到带iframe的页面”,您将看到加载了新的iframe
      </p>
      <iframe src={iframeUrl} width="640" height="480" title="test wikipedia" />
    </div>
  );
};

const App = () => {
  const loc = useLocation();
  console.log(loc);
  return (
    <>
      <ul>
        <li>
          <Link to="/contentpage">Page with content</Link>
        </li>
        <li>
          <Link to="/iframepage">Page with iframe</Link>
        </li>
      </ul>

      <hr />
      <div hidden={loc.pathname !== "/iframepage"}>
        <Page2 />
      </div>
      <Routes>
        <Route exact path="/contentpage" element={<Page1 />} />
        <Route exact path="/iframepage" element={<></>} />
      </Routes>
    </>
  );
};

export default () => (
  <Router>
    <App />
  </Router>
);

<details>
<summary>英文:</summary>
I found a solution, basically I will need to pull the page out of the react-router-dom library and route it manually.
It&#39;s kind of an hacky fix but consider the huge improvement I&#39;ve on speed and usability of the whole UI, I&#39;m willing to take this compromises.
Here is the working example: https://codesandbox.io/s/optimistic-rgb-mmqyss?file=/src/App.js
And just in case it will ever go down and somebody will still need the solution, here is the code:

import React, { useEffect, useState } from "react";
import {
BrowserRouter as Router,
Route,
Routes,
Link,
useLocation
} from "react-router-dom";

function delay(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}

const fakeApi = async () => {
await delay(1000);
return {
src: "https://fr.wikipedia.org/wiki/Main_Page"
};
};

const Page1 = () => <div>Page with sample content</div>;

const Page2 = () => {
const [iframeUrl, setIframeUrl] = useState(null);

const loadIframe = async () => {
const { src } = await fakeApi();
setIframeUrl(src);
};

useEffect(() => {
loadIframe();
}, []);

return (
<div>
<h3>Page with sample iframe</h3>
<p>
Eveytime a users moves to this page the iframe is reloaded (ex. if you
try to scroll, navigate to "Page with content" and back to "Page with
iframe", you'll see a new iframe is loaded)
</p>
<iframe src={iframeUrl} width="640" height="480" title="test wikipedia" />
</div>
);
};

const App = () => {
const loc = useLocation();
console.log(loc);
return (
<>
<ul>
<li>
<Link to="/contentpage">Page with content</Link>
</li>
<li>
<Link to="/iframepage">Page with iframe</Link>
</li>
</ul>

  &lt;hr /&gt;
&lt;div hidden={loc.pathname !== &quot;/iframepage&quot;}&gt;
&lt;Page2 /&gt;
&lt;/div&gt;
&lt;Routes&gt;
&lt;Route exact path=&quot;/contentpage&quot; element={&lt;Page1 /&gt;} /&gt;
&lt;Route exact path=&quot;/iframepage&quot; element={&lt;&gt;&lt;/&gt;} /&gt;
&lt;/Routes&gt;
&lt;/&gt;

);
};

export default () => (
<Router>
<App />
</Router>
);


</details>
# 答案2
**得分**: 0
iFrame 的内容在 React 中没有状态,所以在重新渲染时会被重置。您需要一次性渲染页面上的所有内容,然后使用 CSS 来隐藏和显示内容。
<details>
<summary>英文:</summary>
The content of the iFrame has no state in React, so gets reset when your rerender it. You need to render everything on the page once and then use CSS to hide and show the content.
</details>

huangapple
  • 本文由 发表于 2023年3月9日 21:25:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75685235.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定