Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react/no-unused-state warning in new getDerivedStateFromProps methods #1759

Closed
ghost opened this issue Apr 5, 2018 · 23 comments
Closed

react/no-unused-state warning in new getDerivedStateFromProps methods #1759

ghost opened this issue Apr 5, 2018 · 23 comments

Comments

@ghost
Copy link

ghost commented Apr 5, 2018

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>
    );
  }
}
@brunodequeiroz
Copy link

Having the same issue here

@ljharb
Copy link
Member

ljharb commented Apr 10, 2018

This may be resolved with the next release; I'll leave it open to check.

@IgorMing
Copy link

IgorMing commented May 1, 2018

Same issue here.

@evan-scott-zocdoc
Copy link

Does not seem to be fixed in 7.8.2

@ljharb
Copy link
Member

ljharb commented May 14, 2018

@evan-scott-zocdoc can you file a new issue?

@evan-scott-zocdoc
Copy link

@ljharb I could, but given the issue in this ticket isn't actually fixed and it's recent, shouldn't this just be reopened?

@ljharb
Copy link
Member

ljharb commented May 14, 2018

@evan-scott-zocdoc sure. could you provide the exact code and warnings you get?

@ljharb ljharb reopened this May 14, 2018
@evan-scott-zocdoc
Copy link

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.

@ljharb
Copy link
Member

ljharb commented May 14, 2018

Thanks, looks like it's def still an issue.

adi-mat added a commit to folio-org/ui-users that referenced this issue May 15, 2018
- There is one lint issue which is still WIP according to jsx-eslint/eslint-plugin-react#1759
- ComponentWillUpdate is left as is
adi-mat added a commit to folio-org/ui-users that referenced this issue May 15, 2018
- There is one lint issue which is still WIP according to jsx-eslint/eslint-plugin-react#1759
- ComponentWillUpdate is left as is
@yannickcr
Copy link
Member

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.

@evan-scott-zocdoc
Copy link

Hmm, not sure how I feel about that. Those variable names are a suggestion, not part of the API.

@ljharb
Copy link
Member

ljharb commented May 15, 2018

I think if the method name is getDerivedStateFromProps on the component, then the prop names should be irrelevant?

@bengeorge
Copy link

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

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

@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.

@dmitriyK1
Copy link

I also have this issue after refactoring componentWillReceiveProps into getDerivedStateFromProps, would be nice to have a fix for this

@hms181231
Copy link

eslint versions

{
    "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
};

image

@ljharb
Copy link
Member

ljharb commented Oct 24, 2018

@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.

@Adnan-Bacic
Copy link

Adnan-Bacic commented May 24, 2022

for anyone else getting the same error and ends up here.

i recently updated eslint-config-airbnb from 18.2.1 to the currently newest version of 19.0.4. this means i also updated the peerDependencies, this includes eslint-plugin-react from 7.24.0 to 7.28.0. and i get this error.

eslint-plugin-react already has a 7.30.0 version out, i tried updating, which fixes the problem. and i can see in the release notes that it was fixed in 7.29.3:
https://github.com/jsx-eslint/eslint-plugin-react/releases/tag/v7.29.3

so i guess to fix this error you can either update eslint-plugin-react ahead of eslint-config-airbnb or wait for eslint-config-airbnb to update. personally i will wait for eslint-config-airbnb to update so that i always use the same versions of peerDependencies.

@ljharb
Copy link
Member

ljharb commented May 24, 2022

@Adnan-Bacic the airbnb config uses ^, so it should already give you the latest if you’re following the instructions correctly. The Airbnb config never needs to update anything unless it’s a semver-major update, nor will it publish solely for that.

@Adnan-Bacic
Copy link

@ljharb according to the docs we have to run:

npm info "eslint-config-airbnb@latest" peerDependencies

which shows:

{
  eslint: '^7.32.0 || ^8.2.0',
  'eslint-plugin-import': '^2.25.3',
  'eslint-plugin-jsx-a11y': '^6.5.1',
  'eslint-plugin-react': '^7.28.0',
  'eslint-plugin-react-hooks': '^4.3.0'
}

which arent the latest for any of them.

though i guess the ^ character means we can update to higher versions regardless.

@ljharb
Copy link
Member

ljharb commented May 25, 2022

@Adnan-Bacic yes, it means you can, and it means npm always will, so you’ll always get the latest when you update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests