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

Non sfc function shows "react/no-this-in-sfc" #2010

Closed
jmdsg opened this issue Oct 5, 2018 · 20 comments · Fixed by #2708
Closed

Non sfc function shows "react/no-this-in-sfc" #2010

jmdsg opened this issue Oct 5, 2018 · 20 comments · Fixed by #2708

Comments

@jmdsg
Copy link

jmdsg commented Oct 5, 2018

Hi, i have the following file which does not have a stateless functional component, it does not involve react at all but is showing me the error react/no-this-in-sfc when i call this.connection.

import { ValidatedMethod } from "meteor/mdg:validated-method";
import { SimpleSchema } from "meteor/aldeed:simple-schema";

export const prepareLogin = new ValidatedMethod({
    name: "user.prepare",
    validate: new SimpleSchema({
        // ...
    }).validator(),
    run({ remember }) {
        if (Meteor.isServer) {
            const connectionId = this.connection.id; // react/no-this-in-sfc
            return Methods.prepareLogin(connectionId, remember);
        }
        return null;
    },
});
@ljharb
Copy link
Member

ljharb commented Oct 5, 2018

cc @alexzherdev any chance this is fixed already on master?

@alexzherdev
Copy link
Contributor

No, it's not. This is not in a class, nor in a class method, so our checks are not triggering here. Perhaps we might add a check for a member in an object expression? But then what about this valid, albeit likely rare, use case 😕

const Namespace = {
  Component(props) {
    return <div />;
  }
};

<Namespace.Component />

@ljharb
Copy link
Member

ljharb commented Oct 6, 2018

In this case, we’re determining it’s an SFC because it’s a function that destructured it’s first parameter, and sometimes returning null - but I’d expect that being a property of an object - especially if it’s an object passed to a constructor or a function - should downgrade its confidence so that it doesn’t report. Additionally, the function’s name is not PascalCased.

@alexzherdev
Copy link
Contributor

I don't think we're doing any checks on destructured parameters - but returning JSX or null, sure.

Your point about function's name is interesting. I wonder why this has not been implemented before - I can't think of any drawbacks here. Although I'd probably just say Capitalized, not necessarily PascalCased, just to be safe. I feel like this would fix a lot of false positives.

@ElvenMonky

This comment has been minimized.

@ljharb

This comment has been minimized.

@ElvenMonky

This comment has been minimized.

@ljharb

This comment has been minimized.

@ljharb

This comment has been minimized.

@ElvenMonky
Copy link

Sorry, but I don't see why my comment was marked an off-topic.
Once again, most SFC are arrow functions, which can't have names. So if you'd like to take function name into consideration for "react/no-this-in-sfc" - do it with caution.

@ljharb
Copy link
Member

ljharb commented Oct 10, 2018

Most SFCs aren’t necessarily arrow functions, because the Airbnb style guide forbids them - either way, the absence of a name surely won’t mean it’s not an SFC, but the presence of one might.

@AnabelSalomone
Copy link

I've seen a fix for an issue like this one was made (here: #1995 ), any chance we can have it in a release soon?

@ljharb
Copy link
Member

ljharb commented Dec 28, 2018

v7.12.0 is released. Is this issue still a problem?

@paul-sachs
Copy link

@ljharb i have confirmed that this is still a problem as of v7.14.3 Going to checkout the code and see why exactly it's identifying my example as a functional component.

@connect(state => ({
  someReduxState: state.someReduxState
}))
export default class GroupWebUserWizard extends BaseComponent {
  renderFooter() {
    return <div>{this.formatMessage(...)}</div>
  }
}

@paul-sachs
Copy link

I realize my mistake, my example looks like this:

export default class {
  renderFooter() {
    return () => (
      <div>{this.value}</div>
    );
  }
}

Which is the thing that threw me.

@ljharb
Copy link
Member

ljharb commented Oct 22, 2019

Your arrow function there is considered an SFC.

@paul-sachs
Copy link

paul-sachs commented Oct 23, 2019

I thought so as well, but apparently this passes just fine:

export default class {
  renderFooter = () => () => (
      <div>{this.value}</div>
    );
  }
}

But this doesn't:

export default class {
  renderFooter = () => {
    return () => (
      <div>{this.value}</div>
    );
    }
  }
}

The only difference is that one has a block that returns a function instead of the shorthand for returning a function.

@ljharb
Copy link
Member

ljharb commented Oct 23, 2019

interesting, I’d expect both, or neither, to be detected as a component.

@isachivka
Copy link

isachivka commented Oct 29, 2019

export function wrapWithContext(context, contextTypes, children) {
  class ContextWrapper extends Component {
    static childContextTypes = contextTypes;

    constructor(props) {
      super(props);
      // eslint-disable-next-line react/no-this-in-sfc
      this.state = {};
    }

    getChildContext() {
      return context;
    }

    setProps = (props) => {
      // eslint-disable-next-line react/no-this-in-sfc
      this.setState({ ...props });
    };

    render() {
      return (
        // eslint-disable-next-line react/no-this-in-sfc
        cloneElement(children, this.state)
      );
    }
  }
  return createElement(ContextWrapper);
}

@ljharb
Copy link
Member

ljharb commented Oct 29, 2019

No idea why setProps is an arrow function there (functions should never go in class fields) but certainly that's a clear example of a bug in the rule, thanks!

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