Circular dependencies are an unfortunate fact of life, and I wish we had tools to deal with them, instead of desperately trying to avoid them.
A good test for a UI paradigm is, how do you handle a UI like this:
A = [50] [====| ]
B = [10] [| ]
C = [60] [=====| ]
A + B = C
Where [===| ] things are sliders, all three are changeable, and the relation A+B=C must always hold.The easiest solution is to maintain a fixed order of preference, something like:
values = [a:0, b:0, c:0]
fn onChange(key, value) {
values[key] = value
for (k,v) in values {
if (k !== key) values[k] = adjust(k)
}
}
fn adjust(key) {
switch(key) {
case 'a': return max(0, values[c] - values[b])
case 'b': return max(0, values[c] - values[a])
case 'c': return values[a] + values[b]
}
}
The alternative is to maintain the latest selections made by the user and use that as the iteration order.Whatever approach you go with, the "single source of truth" approach of react/vue/svelte + state (whether it is state in hooks, redux, mobx or whatever) holds. The "values" above is the source of truth, and the components just reflect that.
In other words: from a state point of view you don't have three sliders each with a value but a "three-valued component that happens to be shown as three sliders".
Then that some people make React components change state on render/mount/update, is a different failure, but not really a failure of React as much as a failure of the one using React.
But in general no, React doesn't really prevent you from having a component updating and re-rendering because some state changed, and because of that, changes the state again and thus re-renders again, forever.