0

I'm new to React and am still getting my head around flux. My personal Hello World project is a time tracking/billing app, basically a glorified stopwatch, and I've got stuck.

Essentially there's a <TaskList /> component with multiple <Task /> children. Starting a task creates an Interval stored in the Task component's state, used to update an elapsed time display. Tasks can be started, stopped and resumed, but no two tasks should be running at a time. Starting/resuming a task should stop any others currently running.

My question is how do I instruct the running Task to stop when a new Task is started?

In each of my Task component's componentDidMount methods, they listen for the START event triggered by other Tasks starting and run their own stop() function if one is emitted, but I seem to have found myself with the error: Uncaught Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch..

I would paste my code, but my gut says I've gone about this all wrong and my code is immaterial.

Should I be stopping my other Tasks inside my Store, rather than in my component? That would make sense, but how would I clear my Intervals attached to each Task?

(I was hoping that Rubber Ducking this on SO might help me, but it hasn't).

xcession
  • 268
  • 2
  • 11

2 Answers2

0

Short of setting up a global event system to stop and start each timer based on what another timer is doing since they do not share the same state, than you would want to look at this documentation.

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers

However that way kind of sucks, i would recommend having the parent component that generates the child components's state manage how the children start and stop. the child component would have an onClick={this.props.parentClickEvent} which should tell the parent to start and stop a timer etc... if it needs to know which element was clicked specifically you will want to look at the bind function which has the ability to pass it's (this) value to the parent element.

PythonIsGreat
  • 7,529
  • 7
  • 21
  • 26
0

The Flux way would be to keep all the tasks in a store. How I would do it:

Each task would have a state: 'running' or 'idle' and elapsedTime in seconds. Whenever you start a task from the view an ActionCreator is called. This action creator dispatches "TASK_STARTED" with the task id as payload. The store's dispatch handler listens to this action, and handles which tasks should now be running or idle. The store then emits the change event, and the views update themselves.

The interval could live in the task view (better, subview: TaskClockView), creating an Action every second "TASK_TIME_ELAPSED", with the new task time. The store will update itself and then the view.

RoryKoehein
  • 3,113
  • 1
  • 14
  • 13
  • Re-reading the "where does your state live" bits of the React docs really helped me here, along with your answer. My Store now records whether a task state is running or not, then a component updates a clock when it receives props from the parent to say whether a currently running task exists. – xcession May 12 '15 at 13:23