eslint versions
"eslint": "4.19.1",
"eslint-config-airbnb": "16.1.0",
"eslint-loader": "2.0.0",
"eslint-plugin-import": "2.10.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-mocha": "5.0.0",
"eslint-plugin-react": "7.7.0",
"extract-text-webpack-plugin": "3.0.2",
If the only place you reference state is inside getDerivedStateFromProps then the eslint warning triggers for no-unused-state. See the example below:
import React, { Component } from 'react';
export default class ESLintExample extends Component {
static getDerivedStateFromProps(nextProps, prevState) {
if (prevState.id === nextProps.id) {
return {
selected: true,
};
}
return null;
}
constructor(props) {
super(props);
this.state = {
// This is giving a warning even though it is used inside
// getDerivedStateFromProps
id: 123,
};
}
render() {
return (
<h1>{this.state.selected ? 'Selected' : 'Not selected'}</h1>
);
}
}
Having the same issue here
This may be resolved with the next release; I'll leave it open to check.
Same issue here.
Does not seem to be fixed in 7.8.2
@evan-scott-zocdoc can you file a new issue?
@ljharb I could, but given the issue in this ticket isn't actually fixed and it's recent, shouldn't this just be reopened?
@evan-scott-zocdoc sure. could you provide the exact code and warnings you get?
Sure thing, here's the error:
Users/evan.scott/code/pwa/src/Shared/Modals/addInsuranceModal/addInsuranceModal.js
74:13 error Unused state field: 'initialInsuranceLoad' react/no-unused-state
75:13 error Unused state field: 'insuranceJustChanged' react/no-unused-state
76:13 error Unused state field: 'insuranceWasAccepted' react/no-unused-state
125:21 error Unused state field: 'insuranceJustChanged' react/no-unused-state
✖ 6 problems (4 errors, 2 warnings)
and here's a code sample (I tried to clean it up a bit):
export default function addInsuranceModal(WrappedComponent) {
class AddInsuranceModal extends React.Component {
static displayName = `AddInsuranceModal(${WrappedComponent.name || WrappedComponent.displayName || 'Component'})`;
static WrappedComponent = WrappedComponent;
static propTypes = {
bookingSpotlightIsOn: PropTypes.bool,
insuranceIsAccepted: PropTypes.bool,
locationId: PropTypes.string,
providerId: PropTypes.string.isRequired,
providerName: PropTypes.string,
};
static getDerivedStateFromProps(props, state) {
if (!props.insuranceIsValidating) {
const insuranceIsNoLongerAccepted = (
state.insuranceWasAccepted &&
props.insuranceIsAccepted === false
);
const insuranceJustChangedAndIsNotAccepted = (
state.insuranceJustChanged &&
props.insuranceIsAccepted === false
);
const insuranceNotAcceptedOnInitialLoad = (
props.insuranceIsAccepted === false &&
state.initialInsuranceLoad
);
const newState = { ...state };
const insuranceNotAccepted = (
insuranceIsNoLongerAccepted ||
insuranceJustChangedAndIsNotAccepted ||
insuranceNotAcceptedOnInitialLoad
);
/**
* on desktop, show modal on page load- on mobile, wait until
* user clicks book appointment button
*/
const displayReadyForModal = (
getWindowBreakpoint() > Breakpoints.medium ||
props.bookingSpotlightIsOn
);
if (insuranceNotAccepted && displayReadyForModal) {
newState.showModal = true;
newState.insuranceWasAccepted = props.insuranceIsAccepted;
newState.insuranceJustChanged = false;
newState.initialInsuranceLoad = false;
} else {
newState.insuranceWasAccepted = props.insuranceIsAccepted;
newState.insuranceJustChanged = false;
}
return newState;
}
return null;
}
state = {
initialInsuranceLoad: true,
insuranceJustChanged: false,
insuranceWasAccepted: false,
showModal: false,
};
mounted = false;
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
render() {
return (
<div>
{this.state.showModal && this.renderModal()}
<WrappedComponent
{...this.props}
onChange={this.onChangeInsurance}
/>
</div>
);
}
renderModal() {
const { providerName } = this.props;
return (
<Portal>
<ModalView />
</Portal>
);
}
onChangeInsurance = insurance => {
if (this.mounted) {
this.setState({
insuranceJustChanged: true,
});
}
this.props.onChange(insurance);
};
onClickBookAnyway = () => {
this.props.onClickBookAnyway();
this.onClickCancel();
};
onClickChangeInsurance = () => {
this.props.onClickChangeInsurance();
this.onClickCancel();
};
onClickCancel = () => {
this.setState({ showModal: false });
}
}
return withInsuranceValidation(AddInsuranceModal);
}
Basically it's a typical HOC pattern of wrapping another component.
Thanks, looks like it's def still an issue.
Actually the rule did not detected the usage since you did not used the standard name for the getDerivedStateFromProps arguments (it should be nextProps and prevState instead of props and state).
I don't know if this is fixable without getting a lot of false positive.
Hmm, not sure how I feel about that. Those variable names are a suggestion, not part of the API.
I think if the method name is getDerivedStateFromProps on the component, then the prop names should be irrelevant?
Actually the rule did not detected the usage since you did not used the standard name for the getDerivedStateFromProps arguments (it should be nextProps and prevState instead of props and state).
Just wondering where this 'standard' is defined ? It seems the React docs use props and state.
static getDerivedStateFromProps(props, state)
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
@bengeorge because those were the argument names on componentWillReceiveProps.
It doesn't really matter tho, you shouldn't have to name the arguments anything special.
I also have this issue after refactoring componentWillReceiveProps into getDerivedStateFromProps, would be nice to have a fix for this
Still no progress on this?.. :(
FWIW I have a PR open in #1829.
{
"eslint": "^5.7.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^3.1.0",
"eslint-import-resolver-webpack": "^0.10.1",
"eslint-loader": "^2.1.1",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-react": "^7.11.1",
}
## eslint config
{
rules: {
},
parser: "babel-eslint",
env: {
es6: true,
node: true,
browser: true
},
parserOptions: {
ecmaVersion: 8,
sourceType: "module",
ecmaFeatures: {
jsx: true // enable JSX
}
},
extends: [
"airbnb",
"eslint:recommended",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended"
],
plugins: [
"react",
"jsx-a11y",
"import",
"prettier"
],
settings: {
"import/resolver": {
webpack: {
config: "./build/webpack.config.js"
}
},
"react": {
"pragma": "React",
"version": "16.5.2"
},
},
root: true
};

@Hal-pan please open a new issue with actual text (not screenshots of code, please); commenting on a closed one makes it hard to follow through with a fix.
However, this fix hasn't been released yet - so you may need to wait for the next release before it's fixed.
Most helpful comment
I think if the method name is
getDerivedStateFromPropson the component, then the prop names should be irrelevant?