多次调用子组件构造函数

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/>
        );
    

  

每当父组件刷新时,MainHeaderSubheader 的构造函数就会被调用。这是否意味着它每次刷新时都会创建新的子组件,因为我可以看到子组件的渲染也被多次调用。

【问题讨论】:

constructorHeaderComponent 怎么样?它是否也被多次调用? 确实如此,我还注意到用 ListHeaderComponent=this._renderHeader() 替换 ListHeaderComponent=() =&gt; this._renderHeader() 可以防止这种情况发生并给我正在寻找的行为,这是否意味着匿名函数正在创建 @ 的新实例987654332@ 每次都是这样,这就是为什么 react 将其检测为新组件而从不检查现有组件的原因? React 指南说,使用匿名函数可能会产生副作用,即即使子组件没有更改,子组件也会呈现不必要的内容。 @G_S 所以用实例函数替换我所有的匿名函数是一个好主意,就像声明函数并使用它们的默认方式一样,不仅用于此,还用于网络调用和设置状态来电? 是的。根据反应文档,需要使用 bind() 或类属性语法。 【参考方案1】:

控制您的index.js 文件。如果看到&lt;React.StrictMode&gt;,则应更改为&lt;&gt;。这解决了我的问题。

应该是这样的:

ReactDOM.render(
  <>
    <App/>
  </>,
  document.getElementById('root')
);

【讨论】:

为什么&lt;React.StrictMode&gt; 会导致这种情况? @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 方法时未触发组件构造函数和路由器生命周期挂钩

传递给子组件的原始值在 Angular 2 的构造函数中未定义

复制构造函数被多次调用c ++

多次调用 JSF Backing Bean 构造函数

多次调用构造函数会改变C++中的成员指针地址