首页 > 解决方案 > 来自父 Promise 的子属性

问题描述

我想为我的项目创建一个导航组件。shell获取一个带有章节信息的 json,这些被传递给,nav-element它递归地调用自身来渲染导航树。

外壳.js

import { LitElement, html, css } from 'lit-element';
import {until} from 'lit-html/directives/until.js';
import './nav-element.js';

export class Shell extends LitElement {
  static get properties() {
    return {
      configjson : { type: Array }
    };
  }

  constructor() {
    super();
    this.configjson = fetch('./src/convertjson_test.json').then(res => res.json());
  }

  render() {
    return html`
        <main>
            some content
            <nav-element .chapters=${until(this.configjson, [])} root></nav-element>
        </main>
    `;
  }
}
customElements.define('shell', Shell);

导航元素.js

import { LitElement, html, css } from 'lit-element';
import {until} from 'lit-html/directives/until.js';
import {repeat} from 'lit-html/directives/repeat.js';

export class NavElement extends LitElement {
  static get properties() {
    return {
        chapters: {type: Array},
        root: {type: Boolean} //to mark the root node
    };
  }

  static get styles() {
    return css`
        .navheader {
            display: none;
        }

        .navheader[active] {
            display: block;
        }
    `;
  }

  render() {
    return html`
        <div class="navHeader" ?active="${this.root}">header</div>
        ${until(repeat(this.chapters, (chapter) => chapter.pos, (chapter) => html`<div>${chapter.n}<nav-element .chapters=${chapter.c}></nav-element></div>`))}
    `;
  }
}
customElements.define('nav-element', NavElement);

问题是,configjsonPromise 作为属性传递,并且在调用时尚未解决nav-element,所以我收到错误:

Uncaught (in promise) TypeError: this.chapters is undefined

搜索所有lit-elementlit-html文档,该until指令解决了 . 中的问题shell,但没有解决nav-element. 相同的编码模式在Polymer 2(&3,尽管使用 ajax 而不是 fetch)中运行良好。有谁知道如何仅使用 lit-element 解决这个问题?

标签: lit-elementlit

解决方案


房产的建造NavElement和转让之间有一个时间框架。在组件本身而不是在's指令中进行初始化可能是安全的,或者至少在模板中提供一个后备值:chapterschaptersundefinedchaptersShelluntil

export class NavElement extends LitElement {
  static get properties() {
    return {
        chapters: {type: Array},
        // ...
    };
  }

  constructor() {
    super();
    this.chapters = [];
  }

  // or

  render() {
    return html`
      ...
      ${repeat(this.chapters || [], chapter => ...)}
    `;
  }
}

此外,您已经(正确地)将该chapters属性声明为 anArray但您将repeat指令包装在 an 中until(好像它是Promise我猜的?)。这里有两件事发生:

  • repeat()调用返回 a而DirectiveFn不是alike 期望的。如果是 a ,正确的组合方式是:PromiseuntilchaptersPromiseuntilrepeat

    until(
      this.chaptersPromise.then(chapters => repeat(chapters, chapter => html`...`)),
      html`Loading...`,
    )
    

    但...

  • chaptersis not a Promiseuntil父组件中的调用解析它并传递结果。

至于Shell组件:until以这种方式使用应该可以工作,但是它的预期用途是

渲染占位符内容,直到最终内容可用

[来自lit-html 文档]

要充分利用它,请使用它来临时渲染加载模板,而不是<nav-element>

render() {
  return html`
    ${until(
      this.configJson.then(chapters => html`<nav-element .chapters=${chapters}></nav-element>`),
      html`Loading chapters`,
    )}
  `;
}

此外,没什么大不了的,但这里configJson属性被声明为 anArray但实际上是 a Promise


推荐阅读