Angular Nx项目NgRx逻辑正常但Storybook无法显示bookmark
Angular Nx项目NgRx管理的Bookmark数据无法在Storybook渲染问题定位
核心问题原因
- Storybook运行环境未正确加载依赖
Storybook是独立的组件运行沙箱,不会自动继承主应用或业务库的全局模块配置。你当前的Story配置没有导入NgRx的Store模块、Effects模块、HttpClient模块、浏览器动画模块等必需依赖,也没有正确注册Bookmark对应的reducer和effect,组件实例化时要么注入Store失败,要么dispatch的获取数据action无法被effect处理,根本不会触发数据加载流程。另外你的LibModule中exports数组为空,即使外部导入该模块也无法使用BookmarkListComponent。 - 代码存在复制遗留的拼写与命名错误
- Action枚举中
DELETE_BOOKMARK_SUCCESS的字符串值写为'DELETE_BOOMARK_SUCCESS',BOOKMARK误写为BOOMARK,会导致删除成功的action无法匹配reducer对应分支 - Effect文件中服务名、action导入别名、effect流名称全部保留了之前Todo示例的命名(
todoService、fromTodoActions、deleteTodo$),虽然TS编译不会报错,但提高了隐性bug概率
- Action枚举中
- 组件代码存在缺失与逻辑漏洞
- 组件中声明
bookmarks$: Observable<Bookmark[]>但未从rxjs导入Observable类型,Storybook的严格编译环境下可能导致变量初始化异常 - 模板中空状态判断绑定的
state变量无任何赋值逻辑,初始固定为false,即使无数据也不会触发空提示 - 组件冗余注入了
BookmarksService,实际全量使用NgRx流程,该服务未被调用
- 组件中声明
- 接口环境依赖导致Storybook请求失败
服务中接口地址硬编码为本地json-server地址http://localhost:3000/bookmarks/,如果启动Storybook时json-server未启动、端口被占用或存在跨域限制,HTTP请求会直接失败,且组件未做错误捕获提示,最终表现为列表无数据。
修复步骤
- 修复模块导出配置:在
LibModule的exports数组中添加BookmarkListComponent,允许外部模块(包括Storybook)引用该组件
@NgModule({ // ...其他配置 exports: [BookmarkListComponent] }) export class LibModule {}
- 修正Action枚举拼写错误,统一代码命名:
export enum BookmarkActionsTypes { // ...其他action DELETE_BOOKMARK_SUCCESS = 'DELETE_BOOKMARK_SUCCESS', // 修正BOOMARK的拼写错误 // ...其他action }
同步将Effect中所有Todo相关的命名替换为Bookmark对应命名,避免混淆。
- 补全组件缺失导入,清理冗余代码:在组件顶部添加Observable导入,删除未使用的
BookmarksService注入,补充空状态判断逻辑
import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; // ...其他导入 export class BookmarkListComponent{ bookmarks$ : Observable<Bookmark[]>; noData$: Observable<boolean>; // ... constructor(private _snackBar: MatSnackBar, private store:Store) { this.bookmarks$ = this.store.pipe(select(fromBookmarkSelectors.selectAll)) this.noData$ = this.bookmarks$.pipe(map(items => items.length === 0)) this.store.dispatch(new fromBookmarkActions.GetBookmarks()); } }
- 配置Story的全局依赖:编写BookmarkList组件的story时,在
moduleMetadata装饰器中导入所有必需模块,推荐优先使用mock服务替代真实接口调用,避免依赖本地json-server环境
// bookmark-list.component.stories.ts import { moduleMetadata, Story, Meta } from '@storybook/angular'; import { BookmarkListComponent } from './bookmark-list.component'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { HttpClientModule } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatListModule } from '@angular/material/list'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { BookmarkReducer } from '../../store/reducers'; import { BookmarksEffects } from '../../store/effects'; import { BookmarksService } from '../../services/bookmarks-service.service'; import { of } from 'rxjs'; export default { title: 'Bookmark/List', component: BookmarkListComponent, decorators: [ moduleMetadata({ imports: [ BrowserAnimationsModule, HttpClientModule, MatListModule, MatIconModule, MatButtonModule, MatSnackBarModule, StoreModule.forRoot({ angular: BookmarkReducer }), EffectsModule.forRoot([BookmarksEffects]) ], providers: [ // 使用mock服务替代真实接口,不依赖本地json-server { provide: BookmarksService, useValue: { getBookmarks: () => of([ {id:123456, name:"Zeke", code:"93ac3Walk3r"}, {id:242668, name:"Rex", code:"ShadowMoses"}, {id:849761, name:"Ray", code:"Tanker"} ]), deleteBookmark: () => of(null) } } ] }) ] } as Meta<BookmarkListComponent>; const Template: Story<BookmarkListComponent> = (args: BookmarkListComponent) => ({ props: args, }); export const Default = Template.bind({}); Default.args = { Color: 'black', backgroundColor: '#ffffff' };
- 调整reducer删除逻辑:将
DELETE_BOOKMARK分支的removeOne操作移到DELETE_BOOKMARK_SUCCESS分支中,避免接口请求失败时前端提前删除数据导致状态不一致。
内容的提问来源于stack exchange,提问作者user19122196
相关产品推荐
相关产品推荐

