You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 5与NgRx环境下集成番茄钟定时器技术求助

Hey there! As someone new to Angular and NgRx, integrating a standalone RxJS timer with your taskDetail page (and linking it to the selected task) totally makes sense—let’s walk through how to pull this off smoothly, building on the container-component pattern from the example app.

Integrating Your RxJS Timer with NgRx & TaskDetail Page

1. Add Timer State to Your NgRx Store

First, you’ll want to formalize your timer’s state in the NgRx Store so it can sync with the selected task. Create a dedicated timer feature slice:

  • Define a state interface to track key timer details:
    export interface TimerState {
      isRunning: boolean;
      currentTime: number; // Track in seconds for easy calculation
      linkedTaskId: string | null; // Tie timer to the selected task
    }
    
  • Create actions for timer operations: StartTimer (accepts a taskId), PauseTimer, UpdateTimer, ResetTimer
  • Write a reducer to handle these actions and update the state
  • Build selectors to access timer state easily (e.g., selectIsTimerRunning, selectLinkedTaskId)

2. Move Timer Logic to NgRx Effects

Your existing RxJS timer logic can be wrapped in an Effect to tie it to Store actions. This keeps your component code clean and ensures timer behavior is centralized:

@Injectable()
export class TimerEffects {
  startTimer$ = createEffect(() => 
    this.actions$.pipe(
      ofType(TimerActions.startTimer),
      switchMap(({ taskId }) => {
        // Use your existing RxJS timer logic here (e.g., interval for 1-second ticks)
        return interval(1000).pipe(
          map(() => TimerActions.updateTimer({ 
            currentTime: /* Calculate updated time here */ 
          })),
          // Stop the timer when pause/reset actions are dispatched
          takeUntil(this.actions$.pipe(ofType(TimerActions.pauseTimer, TimerActions.resetTimer)))
        );
      })
    )
  );

  // Auto-reset timer when the selected task changes
  resetOnTaskChange$ = createEffect(() => 
    this.actions$.pipe(
      ofType(TaskActions.selectTask), // Replace with your actual select task action
      map(() => TimerActions.resetTimer())
    )
  );

  constructor(private actions$: Actions) {}
}

3. Connect Timer State to the TaskDetail Container Component

Following the container-component pattern, your container will act as the middleman between the Store and the UI:

@Component({
  selector: 'app-task-detail-container',
  template: `
    <app-task-detail
      [selectedTask]="selectedTask$ | async"
      [isTimerRunning]="isTimerRunning$ | async"
      [currentTimerTime]="formattedTimerTime$ | async"
      (startTimer)="handleStartTimer($event)"
      (pauseTimer)="handlePauseTimer()"
    ></app-task-detail>
  `
})
export class TaskDetailContainerComponent {
  selectedTask$ = this.store.select(selectSelectedTask);
  isTimerRunning$ = this.store.select(selectIsTimerRunning);
  currentTimerTime$ = this.store.select(selectCurrentTimerTime);
  
  // Format raw seconds into MM:SS for the UI
  formattedTimerTime$ = this.currentTimerTime$.pipe(
    map(seconds => `${Math.floor(seconds / 60).toString().padStart(2, '0')}:${(seconds % 60).toString().padStart(2, '0')}`)
  );

  constructor(private store: Store) {}

  handleStartTimer(taskId: string) {
    this.store.dispatch(TimerActions.startTimer({ taskId }));
  }

  handlePauseTimer() {
    this.store.dispatch(TimerActions.pauseTimer());
  }
}

4. Build the TaskDetail UI Component

Your UI component will only handle display and user interactions, delegating state changes to the container:

@Component({
  selector: 'app-task-detail',
  template: `
    <div *ngIf="selectedTask" class="task-detail">
      <h2>{{ selectedTask.title }}</h2>
      <div class="timer-display">{{ currentTimerTime }}</div>
      <button class="timer-control-btn" 
              (click)="isTimerRunning ? pauseTimer.emit() : startTimer.emit(selectedTask.id)">
        {{ isTimerRunning ? '暂停番茄钟' : '开始番茄钟' }}
      </button>
    </div>
  `
})
export class TaskDetailComponent {
  @Input() selectedTask: Task | null = null;
  @Input() isTimerRunning = false;
  @Input() currentTimerTime = '00:00';

  @Output() startTimer = new EventEmitter<string>();
  @Output() pauseTimer = new EventEmitter<void>();
}

This setup ensures your timer is tightly integrated with the selected task state, follows NgRx best practices, and keeps your components focused on their core responsibilities.

内容的提问来源于stack exchange,提问作者David Ruyle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:04:16