HyperHTML - 是否可以在不重新渲染整个组件的情况下更新组件状态 DOM?
HyperHTML - is it possible to update a component state without re rendering the entire component DOM?
我有以下 hyperHTML 组件,一切都按预期工作,唯一的问题是整个组件 DOM 在每次 this.setState()
调用时重新呈现。
我的问题:
有没有办法更新 DOM 上的通知字符串而无需重新呈现整个组件 DOM?
const { hyper } = hyperHTML;
class searchComponent extends hyper.Component {
constructor(data) {
super();
this.setState({ notification: '' });
}
onChange() {
// ...
if ( condition ) {
this.setState(() => ({ notification: 'notification text!' }));
}
// ...
}
async listTags() {
//...
// async content
//...
}
render() {
this.html `
<div id="search_container">
<select name="tags" id="tags_search" class='form-control m0' multiple="multiple" onChange=${this.onChange}>
${{
any: this.listTags(),
placeholder: 'incoming..!',
}}
</select>
<div class="search_notification">
<!-- I want to re render only this part of the DOM -->
${this.state.notification}
</div>
</div>
`
}
}
您的代码中几乎没有陷阱。
首先,onChange
不会按预期工作,您正在失去原样的上下文。您要么只使用 onchange
HTML 事件,然后调用方法 onchange
并简单地使用 this
作为事件侦听器:
const { hyper } = hyperHTML;
class SearchComponent extends hyper.Component {
onchange() {
this instaneof SearchComponent; // true
}
render() { return this.html`
<div id="search_container">
<select onchange=${this}>
${...}
</select>
</div>`
}
}
或者您在构造函数中绑定 onChange
方法。
您还忘记了 return this.html
在 render()
内,如果您想将组件放在 DOM.
上,这是必需的
但是,为了快速演示代码,假设这些是不相关的错误,您需要了解异步世界是异步的。
如果您有一个异步操作,您无法判断该操作是否已解决,您只是将其传递,而这正是您正在做的。
您正在更改组件的状态,希望以前的异步操作不会再次触发。
但是组件如何知道这种状态变化是否会产生不同的布局? TL;DR 答案是它不能,稍微长一点的是你有一个异步的、不相关的行为,附加到每个更新,但你希望该异步行为只被触发一次,而不是每次更新。
可能的解决方案
您可以创建一个子组件作为一部分,并在 SearchComponent
初始化期间实例化一次 (constructor
),或者简单地使用比当前占位符更有意义的占位符。
确实,现在您正在创建像 <select>incoming..!</select>
这样的输出,这对于标准 HTML.
毫无意义
一个 select
可以有 option
个标签,将它用作某些文本的通用容器就像滥用它的潜力。
你想要的是 select
上的 disabled=${this.optionsResolved}
和 ${this.options}
作为其内容的数组。
通过这种方式,您在解析选项时不会有任何变化,一旦发生这种情况,就会有一个正确的选项列表。
你可以在这个Code Pen
中看到一个例子
我有以下 hyperHTML 组件,一切都按预期工作,唯一的问题是整个组件 DOM 在每次 this.setState()
调用时重新呈现。
我的问题:
有没有办法更新 DOM 上的通知字符串而无需重新呈现整个组件 DOM?
const { hyper } = hyperHTML;
class searchComponent extends hyper.Component {
constructor(data) {
super();
this.setState({ notification: '' });
}
onChange() {
// ...
if ( condition ) {
this.setState(() => ({ notification: 'notification text!' }));
}
// ...
}
async listTags() {
//...
// async content
//...
}
render() {
this.html `
<div id="search_container">
<select name="tags" id="tags_search" class='form-control m0' multiple="multiple" onChange=${this.onChange}>
${{
any: this.listTags(),
placeholder: 'incoming..!',
}}
</select>
<div class="search_notification">
<!-- I want to re render only this part of the DOM -->
${this.state.notification}
</div>
</div>
`
}
}
您的代码中几乎没有陷阱。
首先,onChange
不会按预期工作,您正在失去原样的上下文。您要么只使用 onchange
HTML 事件,然后调用方法 onchange
并简单地使用 this
作为事件侦听器:
const { hyper } = hyperHTML;
class SearchComponent extends hyper.Component {
onchange() {
this instaneof SearchComponent; // true
}
render() { return this.html`
<div id="search_container">
<select onchange=${this}>
${...}
</select>
</div>`
}
}
或者您在构造函数中绑定 onChange
方法。
您还忘记了 return this.html
在 render()
内,如果您想将组件放在 DOM.
但是,为了快速演示代码,假设这些是不相关的错误,您需要了解异步世界是异步的。
如果您有一个异步操作,您无法判断该操作是否已解决,您只是将其传递,而这正是您正在做的。
您正在更改组件的状态,希望以前的异步操作不会再次触发。
但是组件如何知道这种状态变化是否会产生不同的布局? TL;DR 答案是它不能,稍微长一点的是你有一个异步的、不相关的行为,附加到每个更新,但你希望该异步行为只被触发一次,而不是每次更新。
可能的解决方案
您可以创建一个子组件作为一部分,并在 SearchComponent
初始化期间实例化一次 (constructor
),或者简单地使用比当前占位符更有意义的占位符。
确实,现在您正在创建像 <select>incoming..!</select>
这样的输出,这对于标准 HTML.
一个 select
可以有 option
个标签,将它用作某些文本的通用容器就像滥用它的潜力。
你想要的是 select
上的 disabled=${this.optionsResolved}
和 ${this.options}
作为其内容的数组。
通过这种方式,您在解析选项时不会有任何变化,一旦发生这种情况,就会有一个正确的选项列表。
你可以在这个Code Pen
中看到一个例子