为什么 componentDidMount 在 react.js & redux 中被多次调用?
Why componentDidMount gets called multiple times in react.js & redux?
我读到 componentDidMount
只调用一次用于初始渲染,但我看到它被渲染了多次。
看来我创建了一个递归循环。
- componentDidMount 调度动作来获取数据
- 收到数据后,它会触发成功操作以将数据存储在 redux 状态。
- 一个父 React 组件连接到 redux store 并具有
mapStateToProps
用于刚刚在上述步骤中更改的条目
- 父级呈现子组件(通过变量以编程方式选择)
- 再次调用子组件的 componentDidMount
- 它调度获取数据的操作
我认为这就是正在发生的事情。我可能是错的。
如何停止循环?
这是以编程方式呈现子组件的代码。
function renderSubviews({viewConfigs, viewConfig, getSubviewData}) {
return viewConfig.subviewConfigs.map((subviewConfig, index) => {
let Subview = viewConfigRegistry[subviewConfig.constructor.configName]
let subviewData = getSubviewData(subviewConfig)
const key = shortid.generate()
const subviewLayout = Object.assign({}, subviewConfig.layout, {key: key})
return (
<div
key={key}
data-grid={subviewLayout}
>
<Subview
{...subviewData}
/>
</div>
)
})
}
组件实例只会挂载一次,删除时会卸载。在您的情况下,它会被删除并重新创建。
key
道具的作用是帮助 React 找到同一组件的先前版本。这样它就可以用新的 props 更新以前的组件,而不是创建一个新的。
React 通常可以在没有键的情况下正常工作,但带有项目的列表除外。它需要一个密钥,以便在重新排列、创建或删除项目时进行跟踪。
在你的例子中,你明确地告诉 React 你的组件与之前的组件不同。您在每个渲染器上都提供了一个新密钥。这会强制 React 将先前的实例视为已被删除。该组件的任何 children 也将被卸载和拆除。
您应该做的是(永远)不要随机生成密钥。键应始终基于组件显示的数据的身份。如果它不是列表项,您可能不需要密钥。如果它是一个列表项,最好使用从数据身份派生的键,例如 ID 属性,或者多个字段的组合。
如果生成随机密钥是正确的做法,React 会为您处理好。
您应该将初始获取代码放在 React 树的根目录中,通常是 App
。不要把它放在一些随机的 child 中。至少你应该把它放在一个组件中,在你的应用程序的生命周期中存在。
将它放在 componentDidMount
中的主要原因是它不会 运行 在服务器上,因为 server-side 组件永远不会被安装。这对于通用渲染很重要。即使您现在不这样做,以后也可能会这样做,最好为此做好准备。
就一个quote:
It's just because we do 2 initial renders in dev mode to avoid getting warnings about mismatched client/server markup when we introduce the devtools. Doesn't affect production.
第一张图-开发模式,第二张-生产模式。
我发现在组件周围使用 <React.StrictMode>
可能会导致多次 componentDidMount
调用。删除它后,双重调用就消失了。
似乎这只发生在开发环境中,而在生产环境中 componentDidMount
即使使用 <React.StrictMode>
也只被调用一次。
“这是用 React 18.1.0 测试的”
我读到 componentDidMount
只调用一次用于初始渲染,但我看到它被渲染了多次。
看来我创建了一个递归循环。
- componentDidMount 调度动作来获取数据
- 收到数据后,它会触发成功操作以将数据存储在 redux 状态。
- 一个父 React 组件连接到 redux store 并具有
mapStateToProps
用于刚刚在上述步骤中更改的条目 - 父级呈现子组件(通过变量以编程方式选择)
- 再次调用子组件的 componentDidMount
- 它调度获取数据的操作
我认为这就是正在发生的事情。我可能是错的。
如何停止循环?
这是以编程方式呈现子组件的代码。
function renderSubviews({viewConfigs, viewConfig, getSubviewData}) {
return viewConfig.subviewConfigs.map((subviewConfig, index) => {
let Subview = viewConfigRegistry[subviewConfig.constructor.configName]
let subviewData = getSubviewData(subviewConfig)
const key = shortid.generate()
const subviewLayout = Object.assign({}, subviewConfig.layout, {key: key})
return (
<div
key={key}
data-grid={subviewLayout}
>
<Subview
{...subviewData}
/>
</div>
)
})
}
组件实例只会挂载一次,删除时会卸载。在您的情况下,它会被删除并重新创建。
key
道具的作用是帮助 React 找到同一组件的先前版本。这样它就可以用新的 props 更新以前的组件,而不是创建一个新的。
React 通常可以在没有键的情况下正常工作,但带有项目的列表除外。它需要一个密钥,以便在重新排列、创建或删除项目时进行跟踪。
在你的例子中,你明确地告诉 React 你的组件与之前的组件不同。您在每个渲染器上都提供了一个新密钥。这会强制 React 将先前的实例视为已被删除。该组件的任何 children 也将被卸载和拆除。
您应该做的是(永远)不要随机生成密钥。键应始终基于组件显示的数据的身份。如果它不是列表项,您可能不需要密钥。如果它是一个列表项,最好使用从数据身份派生的键,例如 ID 属性,或者多个字段的组合。
如果生成随机密钥是正确的做法,React 会为您处理好。
您应该将初始获取代码放在 React 树的根目录中,通常是 App
。不要把它放在一些随机的 child 中。至少你应该把它放在一个组件中,在你的应用程序的生命周期中存在。
将它放在 componentDidMount
中的主要原因是它不会 运行 在服务器上,因为 server-side 组件永远不会被安装。这对于通用渲染很重要。即使您现在不这样做,以后也可能会这样做,最好为此做好准备。
就一个quote:
It's just because we do 2 initial renders in dev mode to avoid getting warnings about mismatched client/server markup when we introduce the devtools. Doesn't affect production.
第一张图-开发模式,第二张-生产模式。
我发现在组件周围使用 <React.StrictMode>
可能会导致多次 componentDidMount
调用。删除它后,双重调用就消失了。
似乎这只发生在开发环境中,而在生产环境中 componentDidMount
即使使用 <React.StrictMode>
也只被调用一次。
“这是用 React 18.1.0 测试的”