#stenciljs #stencils #stencil-component
#stenciljs #трафареты #stencil-component
Вопрос:
import { Component, h, State } from '@stencil/core';
// import '@webcomponents/custom-elements';
import '@clr/core/icon/register';
import { ClarityIcons, plusIcon } from '@clr/core/icon';
ClarityIcons.addIcons(plusIcon);
@Component({
tag: 'tabs-component',
styleUrl: 'tabs-component.css',
shadow: false,
})
export class TabsComponent {
@State() tabs: Array<object> = [
(
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Cloud</button>
</li>
)
];
addTab(onHead = true) {
// debugger
const tab = (
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Dashboard</button>
</li>
);
if (onHead) {
this.tabs.unshift(tab);
} else {
this.tabs.push(tab);
}
console.log(this.tabs);
}
render() {
return (
<div>
<ul id="demoTabs" class="nav" role="tablist">
<li role="presentation" class="nav-item" onClick={() => this.addTab()}>
<cds-icon shape="plus" class="cursor"></cds-icon>
</li>
{this.tabs}
</ul>
<section id="panel1" role="tabpanel" aria-labelledby="tab1">
tab1
</section>
<section id="panel2" role="tabpanel" aria-labelledby="tab2" aria-hidden="true">
tab2
</section>
<section id="panel3" role="tabpanel" aria-labelledby="tab3" aria-hidden="true">
tab3
</section>
</div>
);
}
}
Ответ №1:
Это вопрос ссылочного равенства. Объекты всегда передаются по ссылке, а не по значению, и поэтому два объекта никогда не равны (по ссылке, даже если они содержат одинаковые значения).
Массив является объектом особого типа и поэтому также передается по ссылке. Изменение значения массива не изменяет его ссылку.
Несколько примеров, иллюстрирующих это:
const foo = ['a', 'b'];
console.log(foo === ['a', 'b', 'c']); // false
foo.push('c');
console.log(foo === ['a', 'b', 'c']); // still false
console.log(['a', 'b', 'c'] === ['a', 'b', 'c']); // actually always false
console.log(foo === foo); // always true because it is the same reference
Stencil сравнивает @State()
оформленные члены класса, используя тот же оператор строгого равенства ===
(то же самое касается @Prop()
). Если значение такое же, то компонент повторно не отображается.
В случае вашего tabs
состояния значение this.tabs
является ссылкой на массив, который вы ему присваиваете. Изменение массива (например, this.tabs.push(...)
) изменяет только значение массива, на который ссылается this.tabs
, но не фактическую ссылку, которая хранится в this.tabs
.
Поэтому вам необходимо переназначить this.tabs
, чтобы сообщить Stencil, что этот элемент изменился. Самый простой способ сделать это
this.tabs = [...this.tabs];
который переносит значения массива в новый массив (который возвращает новую ссылку). В качестве альтернативы, что-то вроде this.tabs = this.tabs.slice()
также сработало бы (работает все, что возвращает новый массив).
В вашем случае проще всего изменить ваш addTab
метод на
addTab(onHead = true) {
const tab = (
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Dashboard</button>
</li>
);
this.tabs = onHead ? [tab, ...this.tabs] : [...this.tabs, tab];
}
(т. Е. либо распространяет исходное значение до, либо после нового элемента).
Ответ №2:
Stencil выполняет строгие проверки на равенство ( ===
), чтобы определить, изменилась ли переменная Prop / State, поэтому она не обнаруживает изменения push
и unshift
as. Вы должны убедиться, что заменили массив на новый. Самый быстрый способ сделать это в вашем примере — вручную заменить массив копией после манипуляции:
if (onHead) {
this.tabs.unshift(tab);
} else {
this.tabs.push(tab);
}
this.tabs = [...this.tabs];
Ответ №3:
Похоже, что временная переменная выполняет трюк, странно.
const tempTabs = [...this.tabs];
if (onHead) {
tempTabs.unshift(tab);
} else {
tempTabs.push(tab);
}
this.tabs = tempTabs;
Комментарии:
1. Это не потому, что есть временная переменная, а потому, что
tempTabs
содержит ссылку на другой массив, чемthis.tabs
(с тем же содержимым). Когда вы устанавливаетеthis.tabs = tempTabs
, вы меняете ссылку наthis.tabs
.