从 Angular 12 升级到 Angular 13 后,我身边也出现了同样的问题。我认为当您尝试绑定对象时总是会发生这种情况。我对storybook的代码做了进一步的分析,发现主要问题是storybook在AfterViewInit的StorybookWrapperComponent中设置了绑定。但是我不明白为什么这在以前的 Angular 版本中不是问题,因为如果你考虑整个生命周期,同样的问题应该已经在以前的版本中发生了。更新的 Angular 版本是否在生命周期的行为方面实现了任何新的功能?对无效值可能更严格吗?
Storybook Wrapper 组件(将呈现组件)的代码如下(如您所见, OnInit 未绑定值,AfterViewInit 绑定实际值):
StorybookWrapperComponent.prototype.ngOnInit = function () {
var _this = this;
// Subscribes to the observable storyProps$ to keep these properties up to date
this.storyWrapperPropsSubscription = this.storyProps$.subscribe(function (storyProps) {
if (storyProps === void 0) { storyProps = {}; }
// All props are added as component properties
Object.assign(_this, storyProps); // --> Here the properties are assigned, but not to the actual component which is rendered
_this.changeDetectorRef.detectChanges(); // --> Here we will trigger the rendering which then creates the issue
_this.changeDetectorRef.markForCheck();
});
};
StorybookWrapperComponent.prototype.ngAfterViewInit = function () {
var _this = this;
// Bind properties to component, if the story have component
if (this.storyComponentElementRef) {
var ngComponentInputsOutputs_1 = NgComponentAnalyzer_1.getComponentInputsOutputs(storyComponent);
var initialOtherProps = getNonInputsOutputsProps(ngComponentInputsOutputs_1, initialProps);
// Initializes properties that are not Inputs | Outputs
// Allows story props to override local component properties
initialOtherProps.forEach(function (p) {
_this.storyComponentElementRef[p] = initialProps[p];
});
// `markForCheck` the component in case this uses changeDetection: OnPush
// And then forces the `detectChanges`
this.storyComponentViewContainerRef.injector.get(core_1.ChangeDetectorRef).markForCheck();
this.changeDetectorRef.detectChanges();
// Once target component has been initialized, the storyProps$ observable keeps target component inputs up to date
this.storyComponentPropsSubscription = this.storyProps$
.pipe(operators_1.skip(1), operators_1.map(function (props) {
// removes component output in props
var outputsKeyToRemove = ngComponentInputsOutputs_1.outputs.map(function (o) { return o.templateName; });
return Object.entries(props).reduce(function (prev, _a) {
var _b;
var key = _a[0], value = _a[1];
return (__assign(__assign({}, prev), (!outputsKeyToRemove.includes(key) && (_b = {},
_b[key] = value,
_b))));
}, {});
}), operators_1.map(function (props) {
// In case a component uses an input with `bindingPropertyName` (ex: @Input('name'))
// find the value of the local propName in the component Inputs
// otherwise use the input key
return Object.entries(props).reduce(function (prev, _a) {
var _b, _c;
var propKey = _a[0], value = _a[1];
var input = ngComponentInputsOutputs_1.inputs.find(function (o) { return o.templateName === propKey; });
return __assign(__assign({}, prev), (input ? (_b = {}, _b[input.propName] = value, _b) : (_c = {}, _c[propKey] = value, _c)));
}, {});
}))
.subscribe(function (props) {
// Replace inputs with new ones from props
Object.assign(_this.storyComponentElementRef, props);
// `markForCheck` the component in case this uses changeDetection: OnPush
// And then forces the `detectChanges`
_this.storyComponentViewContainerRef.injector.get(core_1.ChangeDetectorRef).markForCheck();
_this.changeDetectorRef.detectChanges();
});
}
更新
从 6.4.15 升级到 6.4.17 后,这个问题似乎在最新版本的故事书中得到解决,一切正常。