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).
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.