Suppose a parent renders <ChildComponent callback={(value)=>setState(value)} />
. Suppose the parent re-renders. The pointer values of the callback
prop will be different (ie. not triple-equals-equal) but the callback
prop's value is conceptually the same for all intents and purposes. This is a "new value" despite being the "same value". You run into the same problem when the parent creates an object <ChildComponent data={{foo: 'bar', bar: 'noise'}} />
(pointers differ, despite it being the "same" object from a value-type perspective).
You also run into the reverse problem due to mutability. Suppose I say:
var value = {foo: 'bar', bar: 'noise'};
ReactDOM.render(<ChildComponent data={value} />, ...);
value.bar = 'drinks';
ReactDOM.render(<ChildComponent data={value} />, ...);
As you can see, the props have clearly "changed" (ie. componentWillReceiveProps
should get called, so the ChildComponent can respond accordingly), but the values are triple-equals-equal.
In general, there is no way to solve this, except to always call componentWillReceiveProps
any time the values might have changed.
If javascript always used value types (like they do for integers; two renders of integers or strings are always "equal" if they are equal from a value-type definition) for all data types, than this problem would not exist. Also, mutation creates an issue, because the meaning of a value can change (when it is mutated) but is still triple-equals equal to the original prop. But because javascript uses reference equality and supports mutation, you can't rely on triple-equals to tell you if two things are conceptually the same.
I believe the counter argument is around efficiently in checking to see if things actually changed (eg. focussed on the example of simplifying the API around a past conditions) but that the counter argument is not against the principles in general (an example would help in clarifying why the principles are not possible to achieve under all circumstances).
Let's remove the past tense in the exercise (eg.
propsChanged
vsreceiveProps
) and go back to the principles (and adding C raised by @akinnee-gl in facebook/react#3279):(A) simplify code structure / reduce boilerplate
(B) keep props (inputs) separate from state (internal)
(C) allow for shouldComponentUpdate to control the rendering of a component
In this solution space (or a refined / augmented one), is there a way to achieve these principles?
For example (called with an identical signature both at initialization and with any prop changes to reduce code paths):