多次调用子组件构造函数
Posted
技术标签:
【中文标题】多次调用子组件构造函数【英文标题】:Child component constructor called multiple times 【发布时间】:2018-08-18 18:40:04 【问题描述】:我有一个父组件,它是一个包含标题HeaderComponent
的平面列表。这个HeaderComponent
是我创建的一个自定义组件,它包含它自己的 2 个子组件。每当我刷新列表时,我都会将一个布尔值传递给HeaderComponent
,作为传递给它自己的孩子的道具,我这样做是为了检查每个组件是否需要获取新数据。问题是每当父级刷新并设置一个新状态时,子组件的构造函数每次都会被调用。不应该只在父级初始化时调用构造函数,然后所有进一步的调用都涉及调用子级的 shouldComponentUpdate 方法以查看它是否需要更新。
父组件
_renderHeader = () =>
return <HeaderComponent Items=this.state.Data refresh=this.state.refresh/>;
;
render()
console.log("TAG_RENDER render called " + this.state.refresh);
return (
<FlatList
refreshing=this.state.refresh
onRefresh=() =>
console.log("onRefresh");
this.setState(
refresh: true
, () =>
this._fetchData();
);
......
ListHeaderComponent=() => this._renderHeader()
.......
/>
);
标题组件
export default class HeaderComponent extends React.Component
constructor(props)
super(props);
console.debug("HeaderComponent");
render()
return (
<MainHeader Items=this.props.Items/>
<SubHeader refresh=this.props.refresh/>
);
每当父组件刷新时,MainHeader
和 Subheader
的构造函数就会被调用。这是否意味着它每次刷新时都会创建新的子组件,因为我可以看到子组件的渲染也被多次调用。
【问题讨论】:
constructor
的 HeaderComponent
怎么样?它是否也被多次调用?
确实如此,我还注意到用 ListHeaderComponent=this._renderHeader()
替换 ListHeaderComponent=() => this._renderHeader()
可以防止这种情况发生并给我正在寻找的行为,这是否意味着匿名函数正在创建 @ 的新实例987654332@ 每次都是这样,这就是为什么 react 将其检测为新组件而从不检查现有组件的原因?
React 指南说,使用匿名函数可能会产生副作用,即即使子组件没有更改,子组件也会呈现不必要的内容。
@G_S 所以用实例函数替换我所有的匿名函数是一个好主意,就像声明函数并使用它们的默认方式一样,不仅用于此,还用于网络调用和设置状态来电?
是的。根据反应文档,需要使用 bind() 或类属性语法。
【参考方案1】:
控制您的index.js
文件。如果看到<React.StrictMode>
,则应更改为<>
。这解决了我的问题。
应该是这样的:
ReactDOM.render(
<>
<App/>
</>,
document.getElementById('root')
);
【讨论】:
为什么<React.StrictMode>
会导致这种情况?
@Nathan 参考这个链接 - github.com/facebook/react/issues/12856#issuecomment-613145789【参考方案2】:
正如其中一个答案中正确说明的那样,删除严格模式可以解决问题。之所以要这样做,是因为严格模式故意调用了两次“渲染”方法以检测潜在问题。
React 分两个阶段工作:渲染和提交。渲染阶段检查并确定要应用的新更改。并且提交阶段应用它。
渲染阶段生命周期包括以下方法:构造函数、UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps、...、渲染等等。
渲染阶段非常耗时,并且通常会被分成几部分以释放浏览器。在提交阶段之前可能会多次调用渲染阶段(通常非常快)。 由于渲染阶段方法被多次调用,重要的是这些方法都没有任何问题或副作用。
因此,为了突出可能的副作用以使它们易于发现,显式地反应双重调用渲染阶段方法。
您可以在 :https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects 上阅读更多相关信息 :)
【讨论】:
【参考方案3】:严格模式无法自动为您检测副作用,但可以通过使它们更具确定性来帮助您发现它们。这是通过有意双重调用以下函数来完成的:
类组件构造函数、渲染和 shouldComponentUpdate 方法 类组件静态getDerivedStateFromProps方法 函数组件体 状态更新函数(setState 的第一个参数) 传递给 useState、useMemo 或 useReducer 的函数https://reactjs.org/docs/strict-mode.html
如网站所述, 笔记: 这仅适用于开发模式。生产模式下不会重复调用生命周期。
【讨论】:
以上是关于多次调用子组件构造函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 2 中调用其构造函数之前将数据发送或绑定到子组件?
从 Angular2 路由中的子组件调用 router.parent.navigate 方法时未触发组件构造函数和路由器生命周期挂钩