手动跟踪第一个渲染并对其进行操作是否是反模式或错误代码?

问题描述 投票:0回答:1

我正在开发与 MobX 商店配合使用的组件,但遇到了问题。当我转到具有不同项目 ID 的页面时,加载数据后,我会在呈现新数据之前看到以前的数据。因此,我为第一次渲染编写了此检查,这似乎对于准备要渲染的组件很有用,但在我看来,这可能是错误的代码。是这样吗?

"use client"

const Component = (props) => {
   const isFirstRender = useRef(true)

   if (isFirstRender.current) {
      /* some action */
      isFirstRender.current = false
   }

   return (
      /* some jsx */
   )
})
reactjs next.js anti-patterns
1个回答
0
投票

这可能与此处记录的场景相同当道具更改时重置所有状态

下面讨论与这个问题相关的一些要点。

  1. 组件接收一个 props。
  2. 它使用 props 来获取数据。
  3. 由于 fetch 是一个副作用,所以它被写在 useEffect 中。
  4. 我们清楚地知道,useEffect 在组件渲染期间不会运行。
  5. 它仅在组件渲染后运行。
  6. 因此,在 useEffect 之前将会有一次提交或 DOM 更新。
  7. 失败的地方在于:在useEffect之前的DOM更新将始终显示过时的信息,因为它与组件的最新props无关。
  8. 但是,一旦 useEffect 获取了数据,就会立即执行此操作,并通过调用状态设置函数触发另一个渲染。
  9. 因此 UI 将始终仅在第二次渲染时同步。

现在来回答这个问题:

现在这篇文章正在寻求一种解决方案,以避免陈旧或过时的渲染,这种渲染总是在 useEffect 之前发生,这与我们在上面第 7 点中讨论的点完全相同。

可能解决方案的一些背景信息

请注意,组件将在渲染之间保留状态。这意味着通常当函数对象终止调用时,函数对象内声明的所有变量都将丢失。

然而,React 函数对象能够在渲染之间保留状态值。 React 默认的状态保留规则是,只要同一个组件在 UI 渲染树中的相同位置渲染,它就会保留状态。有关此内容的更多信息,请参阅此处保存和重置状态 虽然默认行为适合大多数用例,因此它已成为 React 的默认行为,但我们现在所处的上下文不适合这种行为

我们不希望 React 保留之前的 fetch 这意味着我们需要一种方法来告诉 React 请随着 props 的变化重置状态

。请注意,即使我们成功重置状态,渲染过程和 useEffect 仍将以相同的正常顺序运行。将进行具有最新状态的初始渲染,并在渲染之后运行 useEffect。然而,我们在这里可以实现的改进是,这个初始渲染将使用我们

传递到 useState 的初始值。由于这个初始值是固定值,因此我们始终可以使用它来构建两个状态值的条件渲染 - 加载状态或获取的数据 以下两个示例代码,demo相同。

下面的第一个代码,演示了我们一直在讨论的问题。

app.js

import { useEffect, useState } from 'react'; export default function App() { return <Page />; } function Page() { const [contentId, setContentId] = useState(Math.random()); return ( <> <Content contentId={contentId} /> <br /> <button onClick={() => setContentId(Math.random())}> Change contentId </button> </> ); } function Content({ contentId }) { const [mockData, setMockData] = useState(null); useEffect(() => { new Promise((resolve) => { setTimeout(() => { resolve(`some mock data 1,2,3,4.... for ${contentId}`); }, 2000); }).then((data) => setMockData(data)); }, [contentId]); return <>mock data : {mockData ? mockData : 'Loading data..'}</>; }

试运行

测试计划:点击按钮更改contentId

点击之前的用户界面

enter image description here点击后不到2秒的UI

观察enter image description here

之前的数据保留时间不到2秒,这不是想要的UI。 UI 应更改以通知用户数据加载正在进行。 2 秒后,模拟数据应进入 UI。

下面的第二个代码解决了该问题。

它通过使用属性

key

解决了该问题。该属性在国家保留计划中具有重要意义。

简而言之,现在发生的情况是,如果两次渲染之间的键发生变化,React 将重置状态。 App.js

import { useEffect, useState } from 'react'; export default function App() { return <Page />; } function Page() { const [contentId, setContentId] = useState(Math.random()); return ( <> <Content contentId={contentId} key={contentId} /> <br /> <button onClick={() => setContentId(Math.random())}> Change contentId </button> </> ); } function Content({ contentId }) { const [mockData, setMockData] = useState(null); useEffect(() => { new Promise((resolve) => { setTimeout(() => { resolve(`some mock data 1,2,3,4.... for ${contentId}`); }, 2000); }).then((data) => setMockData(data)); }, [contentId]); return <>mock data : {mockData ? mockData : 'Loading data..'}</>; }

试运行

测试计划:

点击按钮更改contentId

点击前的UI

点击enter image description here后不到2秒的UI

几秒后的界面enter image description here

观察enter image description here

之前的数据没有保留,而是IU显示加载状态,并在实际数据到来后立即更新。这可能是此用例中所需的 UI。

引用

当子级有条件渲染时,React 如何确定应用哪种状态?

© www.soinside.com 2019 - 2024. All rights reserved.