Clarity in expressing how React keeps track of information input in the forms (updating client)
I had some trouble when first reading the code answering the question: When someone changes a value on the "Income" page, how does React keep track of that information?
As I went through the code to answer this question, I had some trouble following some of the functions and props. I think this was in part because some functions/props don't seem to be consistently named across different component levels. I also think some of my confusion might be remedied through better documentation. (Since I am relatively new to React, some of it may be my learning curve.)
The proposed action item: Refactoring to make it more clear how the variables in the "client" state are set.
For reference, here's the process I used to understand the code base better:
I used React Dev Tools to identify the relevant prop, and then searched the code base to find out where it came from. I then started at VisitPage and traced the props down. Some lines were still confusing to me, such as: setTimeProp = getTimeSetter(__) (in CurrentIncomeStep) sharedProps and baseProps especially when used with the spread operator -- trying to figure out exactly what was being sent where.
This is the rough path I followed to try and understand where the values were being kept track of:
utils/CLIENT_DEFAULTS
containers/VisitPage imports CLIENT_DEFAULTS and then sets a variable called clone inside the constructor of the VisitPage component
this.state contains "client" which is set equal to clone
"Step" refers to each tab on the input form
The FormSection component gets "client" passed to it as a prop --> it appears to be defined within the getCurrentStep() function, taking this.steps[step].form
this.steps contains: CurrentBenefitsStep HouseholdStep CurrentIncomeStep CurrentExpensesStep PredictionsStep
CurrentIncomeStep (inside CurrentIncome.js):
setTimeProp = getTimeSetter(__)
setTimeProp passed down to IncomeForm as setClientProperty
IncomeForm is also defined in CurrentIncome.js
setClientProperty calls ensureFuture to propagate values to future properties
CashFlowRow gets ...sharedProps from setClientProperty, including setClientProperty (defined as the ensureFuture function)
CashFlowRow is defined in formHelpers.js
It defines a prop "store: updateClient" where updateClient is a function that calls the setClientProperty prop passed into it
ManagedNumberField gets ...baseProps from CashFlowRow which includes store()
ManagedNumberField contains a Form.Input and passes down to it the props onChange, onFocus, onBlur = this.handleChange, this.handleFocus, this.handleBlur
Form.Input is from the module semantic-ui-react
Thank you for documenting your process! That's incredibly helpful!
I personally agree that the names need to be more consistent and take full responsibility for that inconsistency. Clearing that up sounds like a great idea to me.
getTimeSetter() is a confusing function. I haven't yet come up with a better way to do it. When you set client values, you're either setting 'current' ones or 'future' ones. This lets you decide which one you're setting for that form section. getTimeSetter() returns a function that uses the correct time frame. Maybe the fact that it's so confusing means that it shouldn't be abstracted in that way or maybe it just means it needs a better name. Every form section does need something, though, because it's either setting the 'current' client values or the 'future' client values. Any ideas?
Do you have other thoughts on how to increase clarity here?
What if 'VisitPage.js' had a setClientCurrent() and setClientFuture()? Or, instead of getTimeSetters() we had a getSetClientCurrent(), etc? Would either of those work?
Thoughts from Slack, unedited:
So I was thinking about how the name of the function that sets client values changes and was trying to trace back what my thinking was when creating those names. I think the problem was that the function does change. It's not handed down pure as freshly fallen snow. It goes through mutations for each specific Component to adjust to that Component's needs.
One way to make that visible is to change the name as the function changes, which I attempted to do, but didn't do very well, partly because I just now articulated that need. That is pretty confusing to trace, though. Now I'm trying to figure out other ways to provide clarity.
Another way of dealing with the situation could be to figure out how to create the function in such a way as it wouldn't need to be changed as it's passed down, which would be awesome. If anyone wants to tackle that, that would be great. I'll try it myself if I get a chance.
Latest thought - never change the function that stores the new client data. Instead, use data-transforming functions to always send back the right kind of data. Similar to what we do with inputs to make sure they have valid values.
I'm going to start work on that last idea. I'll assign myself to the issue, but others are welcome to join in.