开发
API
自2022年9月6日起,本文档站不再更新内容,相关文档已迁移至全新“抖音开放平台”前往

provide-inject 跨层通信

基础库 2.62.0 开始支持。

provide-inject 是一种允许祖先组件跨多层向后代组件传递内容的通信方式。

对于层层嵌套的组件,祖先组件可以通过一个 provide 选项来提供数据,后代组件可以通过声明 inject 选项注入(开始使用)这些数据。声明了 inject 选项的组件被称为 inject 组件,为 inject 组件提供数据的祖先组件被称为 provide 组件。provide 组件不需要知道哪些后代组件使用它提供的数据,inject 组件也不需要知道注入的数据来自哪个 provide 组件。

使用前配置

默认情况下,provide-inject 能力是关闭的,如果开发者想使用 provide-inject 能力,需要在 app.json 声明以下字段:

{
  "usingProvide": true
}

开启 provide-inject 能力前,请检查旧代码,如果在 Page 函数或 Component 函数的参数对象中定义了 provideinjectsetProvide 字段之一或在自定义组件的 methods字段中定义了 setProvide 方法 ,请使用其他的名字替换,除非开发者清楚自己确实正在使用 provide-inject 能力。

数据提供与数据注入

假设存在自定义组件 A、B、C 依次嵌套, 结构如下所示。

A
└── B
    └── C

如果需要将组件 A 的某个数据传给组件 C,只需要分别在组件 A 和 组件 C 声明 provide 选项和 inject 选项,代码如下:

// 组件 A 的 js
Component({
  data: {
    app: "toutiao",
  },
  provide() {
    // 返回值就是要提供的数据
    return {
      providedA: this.data.app,
    };
  },
});

// 组件 C 的 js
Component({
  data: {
    c: "douyin",
  },
  inject: ["providedA"], // 从组件 A 中获取 providedA 的值,即 'toutiao'
  ready() {
    this.setData(
      {
        c: this.inject.providedA,
      },
      () => {
        console.log(this.data.c); // 'toutiao
      }
    );
  },
});

provide 说明

  • provide 作为 Component 函数或 Page 函数的参数对象的一个可选字段使用。
  • provide 类型是 function,返回值是一个数据对象,这个数据对象的 key 就是能被 inject 组件检索的属性名,value 是实际提供的值,可以是任何值。
  • provide 函数的 this 指向组件实例本身,因此在函数体内可以通过 this.datathis.propertiesthis.injectthis 分别访问到自身的数据、属性、注入数据和组件方法 。
  • 在组件或页面初始化的时候如果存在 provide 选项并且 provide 选项是一个函数,就会执行 provide 函数。函数的执行时机在自定义组件触发生命周期 created 或页面触发生命周期 load 之前。

inject 说明

  • inject 作为自定义组件的 Component 函数的参数对象的字段使用。
  • inject 声明可以从祖先 provide 组件获取的数据。如果祖先存在多个 provide 组件声明了同一个 key, inject 组件注入此 key 时选择的是最近 provide 组件的 key。
  • inject 类型可能是以下其中一种:
    • string[],每个元素表示注入的 key,需要 provide 组件提供同名的 key 才能拿到注入值到 inject 组件中。
    • object,对象的 key 是 inject 组件注入的 key 名,类型为 string | symbol,inject 组件可以通过 this.inject[key] 访问 provide 组件的数据,value 的类型可以是:
      • string | symbol,表示在 provide 组件搜索用的 key。
      • object,有fromdefault两个可选字段,其中,from 是在 provide 组件中搜索用的 key,用于取别名。比如 a: {from: 'b'} 会将 provide 组件的提供的 b 映射到 inject 组件的 this.inject.a 上;default 是在 provide 组件找不到 key 时使用的默认值,可以是任何类型。如果 default 是一个函数,则找不到 key 时,在组件初始化的时候会自动执行 default 函数,函数的返回值作为 this.inject[key] 的值。

数据的更新

如果需要将组件 A 提供的 providedA 的值更新为其他值, 比如从 this.data.app 更新为 "xigua",可以在 provide 组件中使用 setProvide 函数实现,代码如下:

<!-- 组件 A 的 ttml -->
<button bindtap="methodA">点击更新 provide</button>
// 组件 A 的 js
Component({
  data: {
    app: "toutiao",
  },
  provide() {
    //返回值就是要提供的数据
    return { providedA: this.data.app };
  },
  methods: {
    methodA() {
      this.setProvide({ providedA: "xigua" });
    },
  },
});

// 组件 C 的 js
Component({
  data: { c: "douyin" },
  inject: ["providedA"], // 从组件 A 中获取providedA 的值,即 'toutiao'
  ready() {
    this.setData(
      {
        c: this.inject.providedA,
      },
      () => {
        console.log(this.data.c); // 'toutiao
      }
    );
  },
  observers: {
    //点击组件 A 的 button 后,触发该监听器的执行
    providedA(val) {
      console.log(val); // 'xigua'
      console.log(val === this.inject.providedA); // true
    },
  },
});

setProvide 说明

  • setProvide 是 Component 或 Page 实例上的一个方法。
  • setProvide 类型是 function,函数参数是一个数据对象,数据对象的 key 是 provide 组件需要被更新的 key,必须是 provide 函数返回对象中已经声明过的 key,setProvide 用于更新 provide 组件向后代 inject 组件提供的数据,可以触发 inject 组件的 observers 对更新字段的监听回调。
  • setProvide的执行不会触发页面的渲染。

注入的 key 的别名机制

observers 可以对 this.inject 的字段进行监听,如同对 this.data 的字段监听一样,当 this.inject 的字段和 this.data 的字段重复时,observers 只能监听 this.inject 的字段。inject 组件可以通过给注入的 key 取别名的方式规避 this.inject 的字段和 this.data 的字段重复的问题。代码如下:

// 组件 A 的 js
Component({
  data: {
    app: "toutiao",
  },
  provide() {
    // 返回值就是要提供的数据
    return {
      providedA: this.data.app,
    };
  },
});

// 组件 C 的 js
Component({
  inject: {
    fromProvidedA: "providedA", // 将 providedA 映射成别名 fromProvidedA
  },
  ready() {
    console.log(this.inject.providedA); // undefined
    console.log(this.inject.fromProvidedA); // 'toutiao'
  },
});

// 另一种写法
// 组件 C 的 js
Component({
  inject: {
    fromProvidedA: {
      from: "providedA", // 将 providedA 映射成别名 fromProvidedA
    },
  },
  ready() {
    console.log(this.inject.providedA); // undefined
    console.log(this.inject.fromProvidedA); // 'toutiao'
  },
});

注入的 key 的默认值

如果 inject 组件在 inject 选项声明了一个 key,该 key 无法在任何一个祖先组件中找到,则 this.inject[key]的结果为 undefined。 通过在 inject 选项声明 default 字段的方式,可以在 inject 组件找不到能够提供某个 key 的祖先组件的情况下,将默认值赋给 this.inject[key]。代码如下:

// 组件 C 的 js
Component({
  inject: {
    notExist: {
      default: "tomato",
    },
  },
  ready() {
    console.log(this.inject.notExist); // 'tomato'
  },
});

如果 default 字段声明成一个函数,则取 default 函数的返回值作为 this.inject[key] 的默认值, default 函数的 this 指向组件实例自身。

// 组件 C 的 js
Component({
  data: {
    a: 1,
  },
  inject: {
    notExist: {
      default() {
        return this.data.a + 1;
      },
    },
  },
  ready() {
    console.log(this.inject.notExist); // '2'
  },
});
点击纠错
该文档是否对你的开发有所帮助?
有帮助
没帮助
该文档是否对你的开发有所帮助?
有帮助
没帮助