<Activity> 允许你隐藏和恢复其子组件的 UI 和内部状态。
¥<Activity> lets you hide and restore the UI and internal state of its children.
<Activity mode={visibility}>
<Sidebar />
</Activity>参考
¥Reference
<Activity>
你可以使用 Activity 隐藏部分应用:
¥You can use Activity to hide part of your application:
<Activity mode={isShowingSidebar ? "visible" : "hidden"}>
<Sidebar />
</Activity>当 Activity 边界处于 hidden 状态时,React 将使用 display: "none" CSS 属性在视觉上隐藏 其子项。它还会销毁它们的副作用,清除所有活动的订阅。
¥When an Activity boundary is hidden, React will visually hide its children using the display: "none" CSS property. It will also destroy their Effects, cleaning up any active subscriptions.
隐藏时,子元素仍会根据新的属性重新渲染,尽管优先级低于其他内容。
¥While hidden, children still re-render in response to new props, albeit at a lower priority than the rest of the content.
当边界再次变为 visible 时,React 将显示恢复了先前状态的子元素,并重新创建它们的副作用。
¥When the boundary becomes visible again, React will reveal the children with their previous state restored, and re-create their Effects.
这样,Activity 可以被视为渲染 “后台活动” 的机制。你可以使用 Activity 来维护和恢复内容的 UI 和内部状态,而不是完全丢弃可能再次可见的内容,同时确保隐藏的内容不会产生不必要的副作用。
¥In this way, Activity can be thought of as a mechanism for rendering “background activity”. Rather than completely discarding content that’s likely to become visible again, you can use Activity to maintain and restore that content’s UI and internal state, while ensuring that your hidden content has no unwanted side effects.
属性
¥Props
-
children:你想要显示和隐藏的 UI。¥
children: The UI you intend to show and hide. -
mode:字符串值'visible'或'hidden'。如果省略,则默认为'visible'。¥
mode: A string value of either'visible'or'hidden'. If omitted, defaults to'visible'.
注意事项
¥Caveats
-
如果 Activity 在 ViewTransition 内部渲染,并且由于 startTransition 引起的更新而变得可见,它将激活 ViewTransition 的
enter动画。如果它被隐藏,它将激活其exit动画。¥If an Activity is rendered inside of a ViewTransition, and it becomes visible as a result of an update caused by startTransition, it will activate the ViewTransition’s
enteranimation. If it becomes hidden, it will activate itsexitanimation. -
An Activity that just renders text will not render anything rather than rendering hidden text, because there’s no corresponding DOM element to apply visibility changes to.For example,
<Activity mode="hidden"><ComponentThatJustReturnsText /></Activity>will not produce any output in the DOM forconst ComponentThatJustReturnsText = () => "Hello, World!".
用法
¥Usage
恢复隐藏组件的状态
¥Restoring the state of hidden components
在 React 中,当你想要有条件地显示或隐藏组件时,通常会根据该条件挂载或卸载它:
¥In React, when you want to conditionally show or hide a component, you typically mount or unmount it based on that condition:
{isShowingSidebar && (
<Sidebar />
)}但是卸载组件会破坏其内部状态,这并不总是你想要的。
¥But unmounting a component destroys its internal state, which is not always what you want.
当你使用 Activity 边界隐藏组件时,React 会将其状态 “save” 化以供稍后使用:
¥When you hide a component using an Activity boundary instead, React will “save” its state for later:
<Activity mode={isShowingSidebar ? "visible" : "hidden"}>
<Sidebar />
</Activity>这使得隐藏组件并在之后将其恢复到之前的状态成为可能。
¥This makes it possible to hide and then later restore components in the state they were previously in.
以下示例包含一个带有可扩展部分的侧边栏。你可以按下 “概述” 来显示其下方的三个子项。主应用区域也有一个按钮,用于隐藏和显示侧边栏。
¥The following example has a sidebar with an expandable section. You can press “Overview” to reveal the three subitems below it. The main app area also has a button that hides and shows the sidebar.
尝试展开“概览”部分,然后关闭再打开侧边栏:
¥Try expanding the Overview section, and then toggling the sidebar closed then open:
import { useState } from 'react'; import Sidebar from './Sidebar.js'; export default function App() { const [isShowingSidebar, setIsShowingSidebar] = useState(true); return ( <> {isShowingSidebar && ( <Sidebar /> )} <main> <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}> Toggle sidebar </button> <h1>Main content</h1> </main> </> ); }
概览部分始终以折叠状态显示。因为我们在 isShowingSidebar 翻转到 false 时卸载了侧边栏,所以它的所有内部状态都会丢失。
¥The Overview section always starts out collapsed. Because we unmount the sidebar when isShowingSidebar flips to false, all its internal state is lost.
这是一个完美的 Activity 用例。即使在视觉上隐藏侧边栏,我们也可以保留其内部状态。
¥This is a perfect use case for Activity. We can preserve the internal state of our sidebar, even when visually hiding it.
让我们用 Activity 边界替换侧边栏的条件渲染:
¥Let’s replace the conditional rendering of our sidebar with an Activity boundary:
// Before
{isShowingSidebar && (
<Sidebar />
)}
// After
<Activity mode={isShowingSidebar ? 'visible' : 'hidden'}>
<Sidebar />
</Activity>并查看新的行为:
¥and check out the new behavior:
import { useState } from 'react'; import { unstable_Activity, Activity as ActivityStable} from 'react'; let Activity = ActivityStable ?? unstable_Activity; import Sidebar from './Sidebar.js'; export default function App() { const [isShowingSidebar, setIsShowingSidebar] = useState(true); return ( <> <Activity mode={isShowingSidebar ? 'visible' : 'hidden'}> <Sidebar /> </Activity> <main> <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}> Toggle sidebar </button> <h1>Main content</h1> </main> </> ); }
现在,侧边栏的内部状态已恢复,其实现方式没有任何变化。
¥Our sidebar’s internal state is now restored, without any changes to its implementation.
恢复隐藏组件的 DOM
¥Restoring the DOM of hidden components
由于 Activity 边界使用 display: none 隐藏其子项,因此其子项的 DOM 在隐藏时也会保留。这使得它们非常适合在用户可能再次交互的 UI 部分中维护短暂状态。
¥Since Activity boundaries hide their children using display: none, their children’s DOM is also preserved when hidden. This makes them great for maintaining ephemeral state in parts of the UI that the user is likely to interact with again.
在此示例中,“联系人”选项卡有一个 <textarea>,用户可以在其中输入消息。如果你输入一些文本,切换到“主页”选项卡,然后切换回“联系人”选项卡,草稿消息将丢失:
¥In this example, the Contact tab has a <textarea> where the user can enter a message. If you enter some text, change to the Home tab, then change back to the Contact tab, the draft message is lost:
export default function Contact() { return ( <div> <p>Send me a message!</p> <textarea /> <p>You can find me online here:</p> <ul> <li>admin@mysite.com</li> <li>+123456789</li> </ul> </div> ); }
这是因为我们在 App 中完全卸载了 Contact。当 Contact 选项卡卸载时,<textarea> 元素的内部 DOM 状态将丢失。
¥This is because we’re fully unmounting Contact in App. When the Contact tab unmounts, the <textarea> element’s internal DOM state is lost.
如果我们切换到使用 Activity 边界来显示和隐藏活动选项卡,则可以保留每个选项卡 DOM 的状态。尝试输入文本并再次切换标签页,你将看到草稿消息不再被重置:
¥If we switch to using an Activity boundary to show and hide the active tab, we can preserve the state of each tab’s DOM. Try entering text and switching tabs again, and you’ll see the draft message is no longer reset:
import { useState } from 'react'; import { unstable_Activity, Activity as ActivityStable} from 'react'; let Activity = ActivityStable ?? unstable_Activity; import TabButton from './TabButton.js'; import Home from './Home.js'; import Contact from './Contact.js'; export default function App() { const [activeTab, setActiveTab] = useState('contact'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'contact'} onClick={() => setActiveTab('contact')} > Contact </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'contact' ? 'visible' : 'hidden'}> <Contact /> </Activity> </> ); }
同样,Activity 边界允许我们在不更改其实现的情况下保留联系人选项卡的内部状态。
¥Again, the Activity boundary let us preserve the Contact tab’s internal state without changing its implementation.
预渲染可能可见的内容
¥Pre-rendering content that’s likely to become visible
到目前为止,我们已经了解了 Activity 如何隐藏用户已交互的某些内容,而不会丢弃该内容的短暂状态。
¥So far, we’ve seen how Activity can hide some content that the user has interacted with, without discarding that content’s ephemeral state.
但是 Activity 边界也可以用来准备用户第一次还未看到的内容:
¥But Activity boundaries can also be used to prepare content that the user has yet to see for the first time:
<Activity mode="hidden">
<SlowComponent />
</Activity>当 Activity 边界在其初始渲染期间处于 hidden 状态时,其子项将不会在页面上可见 - 但它们仍会被渲染,尽管优先级低于可见内容,并且不会挂载它们的副作用。
¥When an Activity boundary is hidden during its initial render, its children won’t be visible on the page — but they will still be rendered, albeit at a lower priority than the visible content, and without mounting their Effects.
这种预渲染允许子组件提前加载所需的任何代码或数据,以便稍后当 Activity 边界可见时,子组件可以更快地显示,并减少加载时间。
¥This pre-rendering allows the children to load any code or data they need ahead of time, so that later, when the Activity boundary becomes visible, the children can appear faster with reduced loading times.
我们来看一个例子。
¥Let’s look at an example.
在此演示中,“帖子”选项卡加载了一些数据。按下此按钮后,你将在数据获取过程中看到 Suspense 回退:
¥In this demo, the Posts tab loads some data. If you press it, you’ll see a Suspense fallback displayed while the data is being fetched:
import { useState, Suspense } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Posts from './Posts.js'; export default function App() { const [activeTab, setActiveTab] = useState('home'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'posts'} onClick={() => setActiveTab('posts')} > Posts </TabButton> <hr /> <Suspense fallback={<h1>🌀 Loading...</h1>}> {activeTab === 'home' && <Home />} {activeTab === 'posts' && <Posts />} </Suspense> </> ); }
这是因为 App 在其选项卡处于活动状态之前不会挂载 Posts。
¥This is because App doesn’t mount Posts until its tab is active.
如果我们更新 App 以使用 Activity 边界来显示和隐藏活动选项卡,则 Posts 将在应用首次加载时进行预渲染,从而允许它在可见之前获取其数据。
¥If we update App to use an Activity boundary to show and hide the active tab, Posts will be pre-rendered when the app first loads, allowing it to fetch its data before it becomes visible.
现在尝试点击“帖子”标签页:
¥Try clicking the Posts tab now:
import { useState, Suspense } from 'react'; import { unstable_Activity, Activity as ActivityStable} from 'react'; let Activity = ActivityStable ?? unstable_Activity; import TabButton from './TabButton.js'; import Home from './Home.js'; import Posts from './Posts.js'; export default function App() { const [activeTab, setActiveTab] = useState('home'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'posts'} onClick={() => setActiveTab('posts')} > Posts </TabButton> <hr /> <Suspense fallback={<h1>🌀 Loading...</h1>}> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'posts' ? 'visible' : 'hidden'}> <Posts /> </Activity> </Suspense> </> ); }
得益于隐藏的 Activity 边界,Posts 能够为更快的渲染做好准备。
¥Posts was able to prepare itself for a faster render, thanks to the hidden Activity boundary.
使用隐藏的 Activity 边界预渲染组件是减少用户接下来可能与之交互的 UI 部分加载时间的有效方法。
¥Pre-rendering components with hidden Activity boundaries is a powerful way to reduce loading times for parts of the UI that the user is likely to interact with next.
加快页面加载时的交互速度
¥Speeding up interactions during page load
React 包含一项名为“选择性水合”的底层性能优化功能。它的工作原理是将应用的初始 HTML 分块加载,即使页面上的其他组件尚未加载其代码或数据,也能使某些组件变得可交互。
¥React includes an under-the-hood performance optimization called Selective Hydration. It works by hydrating your app’s initial HTML in chunks, enabling some components to become interactive even if other components on the page haven’t loaded their code or data yet.
Suspense 边界参与选择性水合,因为它们会自然地将你的组件树划分为彼此独立的单元:
¥Suspense boundaries participate in Selective Hydration, because they naturally divide your component tree into units that are independent from one another:
function Page() {
return (
<>
<MessageComposer />
<Suspense fallback="Loading chats...">
<Chats />
</Suspense>
</>
)
}这里,MessageComposer 可以在页面初次渲染时完全加载完毕,甚至在 Chats 加载并开始获取数据之前。
¥Here, MessageComposer can be fully hydrated during the initial render of the page, even before Chats is mounted and starts to fetch its data.
因此,通过将组件树分解为离散单元,Suspense 允许 React 将应用的服务器渲染 HTML 分块合并,从而使应用的各个部分能够尽快实现交互。
¥So by breaking up your component tree into discrete units, Suspense allows React to hydrate your app’s server-rendered HTML in chunks, enabling parts of your app to become interactive as fast as possible.
但是对于那些不使用 Suspense 的页面呢?
¥But what about pages that don’t use Suspense?
以这个标签页为例:
¥Take this tabs example:
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
{activeTab === 'home' && (
<Home />
)}
{activeTab === 'video' && (
<Video />
)}
</>
)
}这里,React 必须一次性将整个页面加载完毕。如果 Home 或 Video 渲染速度较慢,则在 hydration 期间,它们可能会导致选项卡按钮无响应。
¥Here, React must hydrate the entire page all at once. If Home or Video are slower to render, they could make the tab buttons feel unresponsive during hydration.
在活动选项卡周围添加 Suspense 可以解决此问题:
¥Adding Suspense around the active tab would solve this:
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
<Suspense fallback={<Placeholder />}>
{activeTab === 'home' && (
<Home />
)}
{activeTab === 'video' && (
<Video />
)}
</Suspense>
</>
)
}……但它也会改变 UI,因为 Placeholder 的回退会在初始渲染时显示。
¥…but it would also change the UI, since the Placeholder fallback would be displayed on the initial render.
相反,我们可以使用 Activity。由于 Activity 边界可以显示和隐藏其子项,它们已经自然地将组件树划分为独立的单元。与 Suspense 一样,此功能允许它们参与选择性数据同步。
¥Instead, we can use Activity. Since Activity boundaries show and hide their children, they already naturally divide the component tree into independent units. And just like Suspense, this feature allows them to participate in Selective Hydration.
让我们更新示例,在活动标签页周围使用 Activity 边界:
¥Let’s update our example to use Activity boundaries around the active tab:
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
<Activity mode={activeTab === "home" ? "visible" : "hidden"}>
<Home />
</Activity>
<Activity mode={activeTab === "video" ? "visible" : "hidden"}>
<Video />
</Activity>
</>
)
}现在,我们初始的服务端渲染 HTML 看起来与原始版本相同,但由于 Activity 的存在,React 可以在挂载 Home 或 Video 之前先将 Tab 按钮合并。
¥Now our initial server-rendered HTML looks the same as it did in the original version, but thanks to Activity, React can hydrate the tab buttons first, before it even mounts Home or Video.
因此,除了隐藏和显示内容之外,Activity 边界还可以通过让 React 知道页面的哪些部分可以单独交互,从而帮助提高应用在 hydration 期间的性能。
¥Thus, in addition to hiding and showing content, Activity boundaries help improve your app’s performance during hydration by letting React know which parts of your page can become interactive in isolation.
即使你的页面从未隐藏过其部分内容,你仍然可以添加始终可见的 Activity 边界来提高数据同步性能:
¥And even if your page doesn’t ever hide part of its content, you can still add always-visible Activity boundaries to improve hydration performance:
function Page() {
return (
<>
<Post />
<Activity>
<Comments />
</Activity>
</>
);
}故障排除
¥Troubleshooting
我的隐藏组件存在不必要的副作用
¥My hidden components have unwanted side effects
Activity 边界通过在其子项上设置 display: none 并清除其所有效果来隐藏其内容。因此,大多数行为良好且能够正确清理其副作用的 React 组件已经能够很好地抵御被 Activity 隐藏。
¥An Activity boundary hides its content by setting display: none on its children and cleaning up any of their Effects. So, most well-behaved React components that properly clean up their side effects will already be robust to being hidden by Activity.
但在某些情况下,隐藏组件的行为与未卸载组件的行为不同。最值得注意的是,由于隐藏组件的 DOM 不会被销毁,因此即使组件隐藏后,该 DOM 的任何副作用仍将持续存在。
¥But there are some situations where a hidden component behaves differently than an unmounted one. Most notably, since a hidden component’s DOM is not destroyed, any side effects from that DOM will persist, even after the component is hidden.
例如,考虑一个 <video> 标签。通常情况下,它不需要任何清理,因为即使你正在播放视频,卸载标签也会停止在浏览器中播放视频和音频。尝试播放视频,然后在此演示中按下 Home 键:
¥As an example, consider a <video> tag. Typically it doesn’t require any cleanup, because even if you’re playing a video, unmounting the tag stops the video and audio from playing in the browser. Try playing the video and then pressing Home in this demo:
import { useState } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> {activeTab === 'home' && <Home />} {activeTab === 'video' && <Video />} </> ); }
视频按预期停止播放。
¥The video stops playing as expected.
现在,假设我们想要保留用户上次观看的时间码,这样当他们再次跳转回视频时,就不会从头开始。
¥Now, let’s say we wanted to preserve the timecode where the user last watched, so that when they tab back to the video, it doesn’t start over from the beginning again.
这是一个很好的 Activity 用例!
¥This is a great use case for Activity!
让我们更新 App,使用隐藏的 Activity 边界隐藏非活动标签页,而不是卸载它,看看这次演示程序的行为:
¥Let’s update App to hide the inactive tab with a hidden Activity boundary instead of unmounting it, and see how the demo behaves this time:
import { useState } from 'react'; import { unstable_Activity, Activity as ActivityStable} from 'react'; let Activity = ActivityStable ?? unstable_Activity; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'video' ? 'visible' : 'hidden'}> <Video /> </Activity> </> ); }
糟糕!即使标签页被隐藏,视频和音频仍会继续播放,因为标签页的 <video> 元素仍然在 DOM 中。
¥Whoops! The video and audio continue to play even after it’s been hidden, because the tab’s <video> element is still in the DOM.
为了解决这个问题,我们可以添加一个带有清理函数的副作用,用于暂停视频:
¥To fix this, we can add an Effect with a cleanup function that pauses the video:
export default function VideoTab() {
const ref = useRef();
useLayoutEffect(() => {
const videoRef = ref.current;
return () => {
videoRef.pause()
}
}, []);
return (
<video
ref={ref}
controls
playsInline
src="..."
/>
);
}我们调用 useLayoutEffect 而不是 useEffect,因为从概念上讲,清理代码与组件的 UI 视觉隐藏相关。如果我们使用常规效果,代码可能会因为(比如)重新挂起 Suspense 边界或 View Transition 而延迟。
¥We call useLayoutEffect instead of useEffect because conceptually the clean-up code is tied to the component’s UI being visually hidden. If we used a regular effect, the code could be delayed by (say) a re-suspending Suspense boundary or a View Transition.
让我们看看新的行为。尝试播放视频,切换到“主页”标签页,然后返回“视频”标签页:
¥Let’s see the new behavior. Try playing the video, switching to the Home tab, then back to the Video tab:
import { useState } from 'react'; import { unstable_Activity, Activity as ActivityStable} from 'react'; let Activity = ActivityStable ?? unstable_Activity; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'video' ? 'visible' : 'hidden'}> <Video /> </Activity> </> ); }
效果很好!我们的清理函数可确保视频在被 Activity 边界隐藏时停止播放。更棒的是,<video> 标签永远不会被销毁,时间码会被保留,并且当用户切换回来继续观看时,视频本身无需再次初始化或下载。
¥It works great! Our cleanup function ensures that the video stops playing if it’s ever hidden by an Activity boundary, and even better, because the <video> tag is never destroyed, the timecode is preserved, and the video itself doesn’t need to be initialized or downloaded again when the user switches back to keep watching it.
这是一个很好的例子,说明如何使用 Activity 为隐藏的 UI 部分保存短暂的 DOM 状态,但用户可能很快会再次与之交互。
¥This is a great example of using Activity to preserve ephemeral DOM state for parts of the UI that become hidden, but the user is likely to interact with again soon.
我们的示例说明,对于某些标签(例如 <video>),卸载和隐藏的行为有所不同。如果组件渲染的 DOM 具有副作用,并且你希望在 Activity 边界隐藏它时防止该副作用,请添加一个带有返回函数的副作用来清除它。
¥Our example illustrates that for certain tags like <video>, unmounting and hiding have different behavior. If a component renders DOM that has a side effect, and you want to prevent that side effect when an Activity boundary hides it, add an Effect with a return function to clean it up.
最常见的情况来自以下标签:
¥The most common cases of this will be from the following tags:
-
<video> -
<audio> -
<iframe>
不过,通常情况下,大多数 React 组件应该已经足够强大,不会被 Activity 边界隐藏。从概念上讲,你应该将 “hidden” 活动视为已卸载。
¥Typically, though, most of your React components should already be robust to being hidden by an Activity boundary. And conceptually, you should think of “hidden” Activities as being unmounted.
为了快速发现其他未正确清理的副作用(这不仅对 Activity 边界很重要,而且对 React 中的许多其他行为也很重要),我们建议使用 <StrictMode>。
¥To eagerly discover other Effects that don’t have proper cleanup, which is important not only for Activity boundaries but for many other behaviors in React, we recommend using <StrictMode>.
我的隐藏组件包含未运行的副作用
¥My hidden components have Effects that aren’t running
当 <Activity> 为 “hidden” 时,其所有子项的副作用都将被清除。从概念上讲,子组件会被卸载,但 React 会保存它们的状态以供后续使用。这是 Activity 的一项功能,因为它意味着订阅不会对 UI 的隐藏部分生效,从而减少了隐藏内容所需的工作量。
¥When an <Activity> is “hidden”, all its children’s Effects are cleaned up. Conceptually, the children are unmounted, but React saves their state for later. This is a feature of Activity because it means subscriptions won’t be active for hidden parts of the UI, reducing the amount of work needed for hidden content.
如果你依赖副作用挂载来清理组件的副作用,请重构副作用以在返回的清理函数中完成这项工作。
¥If you’re relying on an Effect mounting to clean up a component’s side effects, refactor the Effect to do the work in the returned cleanup function instead.
为了快速查找有问题的效果,我们建议添加 <StrictMode>,它将快速执行 Activity 的卸载和挂载,以捕获任何意外的副作用。
¥To eagerly find problematic Effects, we recommend adding <StrictMode> which will eagerly perform Activity unmounts and mounts to catch any unexpected side-effects.