Using this rule:
"react/destructuring-assignment": [
"warn",
"always",
{
"ignoreClassFields": true
}
],
This code:
export default class Thing extends React.Component {
state = {
alpha: false,
beta: this.props.beta,
charlie: null,
};
// ...
}
Generates this warning:
[eslint] Must use destructuring props assignment (react/destructuring-assignment)
Version information:
$ npm ls eslint
@centriam/[email protected] /Users/adam.babcock/Source/cxlint/client
βββ [email protected]
βββ¬ [email protected]
β βββ [email protected] deduped
βββ¬ [email protected]
βββ [email protected] extraneous
$ npm ls eslint-plugin-react
@centriam/[email protected] /Users/adam.babcock/Source/cxlint/client
βββ [email protected]
βββ¬ [email protected]
βββ [email protected] extraneous
I think that this is a bug, but also, you shouldnβt ever be using props in initial constructor state - you want getDerivedStateFromProps. Otherwise when props change, you might forget to update βbetaβ
@ljharb Agreed. I'm going through existing code applying lint fixes and this situation popped up. The whole pattern in this particular file needs to be rewritten / refactored but for now I'm focusing on lint issues.
What about uncontrolled components though? If the component accepts a "defaultValue" prop, I think it only needs to be "translated" to state once on initialization, and after that the value is managed via component's state.
Thatβd be an edge case, and even then Iβd say the component should rerender when it gets an updated prop.
Whenever I'm in the case of having to use props in state definition, I avoid the warning by using the constructor.
export default class Thing extends React.Component {
constructor(props) {
super(props);
this.state = {
alpha: false,
beta: props.beta,
charlie: null,
};
}
// ...
}
About getDerivedStateFromProps, the following React post recommends avoiding it most of the time. One of the preferred solutions uses props in state definition (Fully uncontrolled component with a key)
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
@Jmenache note that your pattern is not correct unless you also use setState in componentWillReceiveProps - and the replacement for that pair is indeed to use gDSFP.
@ljharb I think the post recommends using a key instead of componentWillReceiveProps with this pattern, so that it creates a new component and goes through the constructor again.
Certainly that's another workaround, but that seems much less performant and clean.
@ljharb As counter intuitive as it is, the article explains that it is usually not slower, and sometimes faster.
Note
While this may sound slow, the performance difference is usually insignificant. Using a key can even be faster if the components have heavy logic that runs on updates since diffing gets bypassed for that subtree.
I agree it is not pretty and I would most likely try using the other recommended solution if I have a choice, but this pattern helped me a few times dealing with legacy code.
Most helpful comment
What about uncontrolled components though? If the component accepts a "defaultValue" prop, I think it only needs to be "translated" to state once on initialization, and after that the value is managed via component's state.