Search code examples
reactjsreduxflux

Can you handle state in this example without Redux or Flux, and if so how would you go about doing it?


Suppose I have a timer structured so that you can view and time multiple projects at once, and within each project you can view and time multiple tasks. Since this is a timer, you can only time one task at a time, and therefore one project at a time.

Because of these restrictions, I've separated the timer into three separate structures:

  • TimerContainer (outer, holds and displays all project objects)
  • ProjectContainer (middle level, holds only one project, with all tasks associated with the project)
  • TaskContainer (inner level, holds only one task).

Only the TimerContainer and ProjectContainer hold state.


TimerContainer:

The TimerContainer doesn't know anything about the tasks, but it does the initial API call to seed all projects and tasks with starting values. The TimerContainer is also concerned with which project is currently tracking time (i.e. holds a projectID value for whichever project is currently timing).


ProjectContainer:

Each ProjectContainer holds information about which task is currently timing (if any), and updates (both here and via an API call) the time spent on each task after they've completed timing. At that time it informs the TimerContainer it (that project) is no longer timing.

As props the TimerContainer is giving ProjectContainer the currently tracking project ID, list of tasks and their seed values, and various project information.


Here is my question: If I update the TimerContainer's "Currently Tracking ProjectID" value, it will trigger a re-rendering of all the ProjectContainers, including the one that just updated one of its tasks' times. That, in my mind, seems to revert it back to the original seed value of that task unless I update the (now static) seed information held in the TimerContainer for that specific task.

If I do that, it makes me think that I have to set the state for both the seed information and the currently tracking projectID with the same call, because if I do it sequentially I'm not sure if it will get to the second state change request.

If this is indeed a problem (and please feel free to say otherwise), I imagine it could be alleviated by Redux or Flux, but given an already established architecture I would like to see if there are clean ways of handling this without bringing in another library first.


Bottom line, how is this solved cleanly without another library?



Update:

It seems as if I was confused about the way re-rendering affected state initialization (namely, it doesn't). I modified Adam's example below to prove that to myself (link here )

After that realization, the solution to my problem simply becomes writing up a function that would handle "Currently Tracking ProjectID" prop value change on each of the ProjectContainers.

Another thing to implement is the shouldComponentUpdate function (thanks again) by checking if the ProjectID was related to that ProjectContainer.


Solution

  • A component re-rendering shouldn't cause that component to lose it's internal state. Here's an example: the child component re-renders because the parent changes state and passes the child new props, but the child keeps its own internal state.

    As far as design options in general, there are a bunch. Here are a few I'd consider:

    • Re-rendering is a performance hit, so consider customizing the shouldComponentUpdate function for child components to keep them from rerendering
    • Try to make as many child components stateless or pure as possible
    • Consider not persisting the "seed" values in the parent component - not sure if there's value to knowing the initial value, but if you just pass that down to the child components, they can store and increment that

    On the whole though, it sounds like you might benefit from a store. Being able to separate out organization of state from functionality can be helpful.