Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage 模型 - 页面及组件生命周期 #49

Open
cnwutianhao opened this issue May 19, 2024 · 0 comments
Open

Stage 模型 - 页面及组件生命周期 #49

cnwutianhao opened this issue May 19, 2024 · 0 comments

Comments

@cnwutianhao
Copy link
Owner

cnwutianhao commented May 19, 2024

示例代码:

@Entry
@Component
struct Index {
  @State show: boolean = true

  build() {
    Column() {
      Button('show')
        .onClick(() => {
          this.show = !this.show
        })
      if (this.show) {
        ComponentA()
      }
    }
  }
}

@Component
struct ComponentA {
  build() {
    Row() {
      Text('Component A')
    }
  }
}

如示例代码所示,这是一个 Column 容器,里面有一个 Button 按钮,当点击这个按钮,会修改变量 show 的值,如果 show 为 true,就会渲染 ComponentA。

尽管他俩都是自定义组件,但是他俩的角色是不一样的。ComponentA 是被 Index 引用的,所以可以理解为 ComponentA 是 Index 的子组件,Index 加上了 @entry 装饰器,也就是这个页面的入口组件。

因此,一个页面要加载,首先会加载入口组件 Index,一个组件要加载,先创建组件实例。但是呢,示例创建出来不代表页面就有了,因为组件对应的页面是靠 build 函数绘制的,所以,在组件实例化以后必须执行 build 函数。当 build 函数全部执行完成,页面才算绘制完成。在示例代码中,调用了 ComponentA,也就是说,在绘制的时候用到了别的组件,也就需要把 ComponentA 加载进来。加载 ComponentA 也需要先创建组件实例再去执行 build 函数。在入口组件当中,不管用到了多少个子组件,都必须把子组件实例创建出来,执行子组件 build 函数,再回过头执行入口组件的代码。当 build 函数内所有子组件包括它自己全部加载完成,页面才能真正绘制成功,也就可以展示页面了。但是呢,页面加载出来,用户访问过程中,必然会去做各种各样的操作,不可能一直停留在这个页面,所以,当用户返回跳转新页面,都有可能离开当前页面,当前页面就会从展示页面变成隐藏页面。如果页面隐藏了,页面中组件是隐藏还是销毁呢?不一定,这去取决于当前页面在隐藏后有没有被销毁,假如我们利用 router.pushUrl() 去做跳转,新页面创建出来,会入栈,放到栈顶,原来的栈顶的会被压到栈内部,并没有被销毁,只是隐藏了,这时候,对应的组件还在;如果页面跳转采用 router.replaceUrl(),那么创建的新页面会压入栈中,放入栈顶,原来的栈顶直接销毁,也就会销毁组件,入口组件都销毁了,也就会销毁子组件实例。不仅仅是跳转,在返回时,会把栈顶的页面移除并销毁,然后把紧挨着栈顶的给挪上来,这时候原先栈顶的页面被销毁了,它所对应的组件也就被销毁了。反过来,如果页面还在,是不是说它里面所有组件也一定也在呢?可不一定,示例代码中,Button 按钮点击会修改 show 的值,show 默认是 true,所以对应的 ComponentA 一上来就会被渲染出来。但是如果现在点击按钮,会把 show 从 true 变成 false,ComponentA 就不能再渲染,本来已经渲染好了,现在不再需要,那么这个 ComponentA 会被销毁。所以页面还在,但组件没了。所以,用户在操作的过程中,很有可能会导致部分子组件被销毁,所以子组件有没有被销毁跟页面跟页面并没有必然的联系。

以上就是页面及组件从创建到销毁完整的生命周期。在这个过程中,Stage 模型提供了一些生命周期的钩子,允许我们在其中完成我们想要做的事:

  1. 组件实例创建成功以后,build 函数执行以前,这里呢有一个钩子,叫 aboutToAppear。可以在这里面完成对一些数据的初始化,初始化以后,在 build 函数里就可以利用数据完成渲染。

  2. 在组件被销毁之前还有一个钩子,叫 aboutToDisappear,可以在这里面完成数据持久化等保存操作。

  3. 页面展示之后有一个钩子,叫 onPageShow

  4. 页面隐藏之前有一个钩子,叫 onPageHide

  5. 当用户点击返回上一页时有一个钩子,叫 onBackPress

注:onPageShowonPageHideonBackPress 都属于页面生命周期钩子,而 aboutToAppearaboutToDisappear 则属于组件生命周期钩子。页面展示肯定是从入口组件开始的,因此页面生命周期钩子只能在加了 @Entry 装饰器的入口组件中使用,普通的自定义组件里不能使用。而跟组件生命周期钩子可以在入口组件,也可以在任何普通自定义组件中使用。

如图所示:

总结:

页面和组件的生命周期主要有五个,aboutToAppear 是在组件创建之后然后 build 函数执行之前去触发,往往在这里做一些数据初始化和准备工作,准备好了以后 build 再去执行,就可以利用这些数据完成渲染。然后是页面的生命周期,页面展示出来就会有 onPageShow,页面被隐藏就会有 onPageHide,点击返回就会有 onBackPress,也可以在这三个里面做一些功能性的逻辑。最后是 aboutToDisappear,这个是在组件被销毁时,组件被销毁有可能一些关键性的数据需要去做保存,所以这里面可以做一些数据保存或者资源释放之类的操作。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant