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

Rule require-default-props does not support default parameters in stateless function #1009

Closed
preco21 opened this issue Dec 22, 2016 · 67 comments

Comments

@preco21
Copy link
Contributor

preco21 commented Dec 22, 2016

Hello, I just got some error from require-default-props rule:

`react/require-default-props`:  propType "foo" is not required, but has no corresponding defaultProp declaration.
`react/require-default-props`:  propType "baz" is not required, but has no corresponding defaultProp declaration.

Here is the code:

function Header({
  foo = true,
  bar,
  baz = () => { /* noop */ },
}) {
  return ...;
}

Header.propTypes = {
  foo: PropTypes.bool,
  bar: PropTypes.bool.isRequired,
  baz: PropTypes.func,
};

I expected there is no error, but seems it causes the problem.

Any ideas?

@ljharb
Copy link
Member

ljharb commented Dec 22, 2016

Default values are not the same as defaultProps. The rule correctly reports this as an error.

@preco21
Copy link
Contributor Author

preco21 commented Dec 23, 2016

If so..

But I guess this kind of pattern is commonly used on stateless functions. So, this is reasonable to me.

In order to realize this pattern works, may I request another rule or option?

@ljharb
Copy link
Member

ljharb commented Dec 23, 2016

That's why it's an important rule - it's bad to use default values instead of defaultProps.

I suppose we could make an option that allows default values but I think the existence of the option would be harmful.

@steida
Copy link

steida commented Dec 24, 2016

@ljharb Correct me if I am wrong, but this rule is unnecessary when we use flowtype.

@ljharb
Copy link
Member

ljharb commented Dec 24, 2016

@steida i don't understand why it would be - defaultProps provide important information to the React runtime that default values can't possibly provide. Flowtype replaces propTypes - information that React doesn't actually use at runtime in production.

@steida
Copy link

steida commented Dec 24, 2016

Yeah, but if you have flowtyped everything, you need runtime checking only at application boundaries.

@ljharb
Copy link
Member

ljharb commented Dec 25, 2016

@steida again, you're talking about propTypes. defaultProps are different, and control runtime behavior - not type-checking. Using default values prevents React from being able to make some kinds of optimizations.

@steida
Copy link

steida commented Dec 25, 2016

I don't want to use defaulProps https://twitter.com/estejs/status/812491172438560769

@steida
Copy link

steida commented Dec 25, 2016

As for optimizations, link pls?

@ljharb
Copy link
Member

ljharb commented Dec 25, 2016

@steida There's no need for a link - by spec, default values are re-evaluated on every invocation of the function. defaultProps, on the other hand, are evaluated once and cached at the module level - across every invocation of the function. Even if React does nothing with regard to them (which I doubt, but haven't bothered to dig up evidence of), defaultProps are more performant than default values.

If you don't want to use defaultProps, disable this rule. If you want flow annotations to be equivalent, make sure that your Flow annotations transpile down to defaultProps, and then this rule can and should be adapted to support them - until that time, they're not the same, and defaultProps is staunchly recommended.

@ljharb ljharb closed this as completed Dec 25, 2016
@bradennapier
Copy link

Hmm - yet the documentation for Flow / React specifically tell you to use default values this way and actually would not support propTypes.

// @ https://flow.org/en/docs/frameworks/react/
let MyComponent = ({ foo, bar = 2 }: { foo: number, bar?: number }) => {
  return <div>{foo + bar}</div>;
};

@ljharb
Copy link
Member

ljharb commented Jul 1, 2017

The documentation for React suggests a number of bad practices amidst all the good ones - just because they make the framework doesn't mean they're always right :-)

@bradennapier
Copy link

#truth -- I switched to using defaultProps already and working well. Would be cool to have a plugin to automatically convert to defaultProps in this situations -- although I know there could be times default parameters are the desired effect (when it executes a function, etc).

@AlexanderTserkovniy
Copy link

AlexanderTserkovniy commented Dec 6, 2017

Hi guys,

In my opinion there should be at least an option to tell that require-default-props should pass if there is default parameter is set.

const Button = ({
  children = 'Cancel', intent = 'primary', className, size, loading = false, ...rest
}) => (
  <button
    {...rest}
    className={classnames(styles[intent], className, {
      [styles[`size-${size}`]]: size,
      [styles['loading-disabled']]: rest.disabled && loading,
    })}
  >
    {loading ? <Spinner height="100%" /> : children}
  </button>
);

intent in this case has default parameter (defaultProp). I do not want to repeat myself, if I write default parameter for some property in function arguments that should be considered as defaultProp.

Would you be so kind to add this option?

@ljharb
Copy link
Member

ljharb commented Dec 6, 2017

That’s not included intentionally; react components (SFCs included) should simply not use default arguments at all.

@abalbanyan
Copy link

reactjs/rfcs#107
defaultProps will eventually be deprecated on function components. Knowing this, it would be nice to have support for enforcing default values for optional props.

@ljharb
Copy link
Member

ljharb commented Jun 28, 2019

Not "will" - that's not merged yet.

@nathggns
Copy link

@ljharb can you please expand on your opposition to default arguments. Considering the React team seems pretty set on deprecating them for function components, and for good reason, what is your opposition to them? Or at the very least, what is your opposition to supporting it as an option? It seems you're out of step with where the React team is going.

It seems to be that defaultProps are at the very least less performant, as they are resolved on every call to React.createElement?

Our team is moving to use default arguments instead of defaultProps for function components, but we use this rule. It would be good for it to support default arguments too.

@bvaughn
Copy link
Contributor

bvaughn commented Jul 10, 2019

defaultProps provide important information to the React runtime that default values can't possibly provide

Using default values prevents React from being able to make some kinds of optimizations.

I know this is an older thread, but I noticed it because it was referenced by a new RFC. Can you clarify what info and optimizations these comments were referring to?

To my knowledge, React does not use defaultProps for anything other than filing in default values for undefined props. May also be worth pointing out that defaultProps are not even supported for some newer types, e.g. forwardRef.

@ljharb
Copy link
Member

ljharb commented Jul 10, 2019

@bvaughn at the time i made that comment, my understanding was that this was planned, but never materialized.

@ljharb
Copy link
Member

ljharb commented Jul 10, 2019

@nathggns what is planned to be deprecated isn’t relevant until it actually is deprecated.

However, in particular, defaultProps can be read and reflected on by HOCs and runtime tools attempting to inspect components, where default arguments can not - so i hope the RFC doesn’t land (even if it’s very likely to do so).

@nathggns
Copy link

@nathggns what is planned to be deprecated isn’t relevant until it actually is deprecated.

I genuinely don't understand how you can believe this to be true. People are writing code now, and people can see what the React team is planning, and its pretty clear that defaultProps for function components is going away. Therefore people will want to write code now that doesn't use defaultProps. But they very quickly have to choose between changing the tooling, disabling it, or writing code they know is going to be deprecated in the near future. That's not good situation to be in.

It is also the case that if you know a feature is going to be deprecated in the future, that people making tooling that people depend on should be prepared for it. It makes no sense at all to wait literally until the release deprecating the feature before beginning to prepare options for avoiding the use of that feature.

TL;DR: people know that defaultProps is going to be deprecated. That genie is out of the bottle. The question now is whether people making tooling are going to prepare for that now or later, and I don't understand why you would pick later.

@ljharb
Copy link
Member

ljharb commented Jul 10, 2019

I assume React, like it usually does, will do the responsible thing and release a codemod to convert defaultProps to default arguments (assuming this change happens) - and at the same time, this plugin will add an autofixable rule to enforce defaultProps placement on function components.

I'd pick later because nothing is certain until it's released - parts of hooks, for example, changed prior to release in ways that would have been complicated to transition alpha support to.

@nathggns
Copy link

I agree that nothing is certain until its released, but even if React decides not to deprecated defaultProps (which seems quite unlikely at this point), people are using default arguments now. People believe it is going to be deprecated and are therefore avoiding it. Is it your opinion that that is a mistake?

@danielkcz
Copy link

danielkcz commented Jul 10, 2019

@nathggns Sorry, but why do you see it as such a problem to simply disable this rule and do the default arguments right away? It's not mandatory to use rules that are most likely obsolete.

Edit: Sure, you don't have the rule to help you writing default arguments, but is it such a pain? Personally, I rather rely on TypeScript than some linter telling me what to do.

@bvaughn
Copy link
Contributor

bvaughn commented Jul 11, 2019

I’d just want the docs to advise doing what react, and thus the react ecosystem, first-class supports - which at this time is defaultProps.

I think this seems a bit misleading. Default parameters are a language feature so React and the ecosystem don't really need to "support" them. Maybe you're referring to the fact that if both default parameters and defaultProps are used, defaultProps will "win"?

@danielkcz
Copy link

danielkcz commented Jul 11, 2019

the react ecosystem, first-class supports - which at this time is defaultProps.

No offense, but you might be slightly behind (perhaps even biased?) on what react ecosystem does. Have a look at any new library that uses function components. I tried a few I can recall and haven't seen a defaultProps that much. So I would dare to say that people are getting comfortable with that deprecation fairly quickly :)

https://unpkg.com/react-router-dom@5.0.1/cjs/react-router-dom.js
https://unpkg.com/formik@next/dist/formik.umd.development.js (single one, it's still WIP)
https://unpkg.com/react-select@3.0.4/dist/react-select.cjs.dev.js

@bvaughn
Copy link
Contributor

bvaughn commented Jul 25, 2019

FYI facebook/react#16210

@danielkcz
Copy link

danielkcz commented Jul 26, 2019

@nathggns I wonder will you be able to work on PR for the new rule? Considering the linked PR (now merged), it's confirmed that React 17 will drop defaultProps on functional components.

Also, shouldn't the current rule warn about deprecation? React will warn in runtime, but would be nice to have a warning in linter as well.

@ljharb What are your thoughts here after your involvement in the facebook/react#16210?

@nathggns
Copy link

@FredyC I almost feel like there's two rules to come out of this

one to prevent use of defaultProps on function components, and one to ensure that every prop used that isn't required has a default value.

Should we make two new issues for this? I'm not sure if the rules have a naming convention or not.

@danielkcz
Copy link

danielkcz commented Jul 29, 2019

@nathggns Well, I am convinced that current require-default-props rule should be tweaked and have deprecation warning for functional components. A new rule to check for default argument values should be made. Otherwise, I think it's too soon to be preparing another enforcing rule until React 17 comes out.

@nathggns
Copy link

@FredyC

I am convinced that current require-default-props rule should be tweaked and have deprecation warning for functional components

This seems like an odd place to put such a deprecetation warning, would it not be better to have a no-sfc-default-props rule or something?

@danielkcz
Copy link

danielkcz commented Jul 29, 2019

People might have this rule enabled and it is forcing them to set defaultProps on functional components without them knowing it's a deprecated pattern. They would need to consciously be aware of the deprecation to enable a new rule unless it would be added to recommended preset. And even with that, there would be suddenly two contradicting rules.

@nathggns
Copy link

@FredyC That's a fair point. Maybe this rule should be deprecated in favour of two new rules – one disabling defaultProps for function components and one requiring them only for class components?

@danielkcz
Copy link

danielkcz commented Jul 29, 2019

That's what I was mostly suggesting :)

Well, I am convinced that current require-default-props rule should be tweaked and have deprecation warning for functional components

There is probably no reason for deprecating that rule for class components and disturb users with that.

Only new rule at this point should be about the proper use of default argument values and that's what we have been talking about for a while here ... #1009 (comment)

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

The first step is that require-default-props should add an option that can disable warning on defaultProps for SFCs. When the react version is 17+, for example, we can default this option to be on.

A different rule should exist that warns when defaultProps is used on SFCs; ideally doing nothing until the version of React that deprecates it (perhaps the next one, but not any of the current ones).

@danielkcz
Copy link

danielkcz commented Jul 30, 2019

The first step is that require-default-props should add an option that can disable warning on defaultProps for SFCs. When the react version is 17+, for example, we can default this option to be on.

That option should be enabled by default now because of defaultProps for FC (not SFC anymore) is deprecated now. Why do you want to be misleading users and forcing them to use defaultProps? If they are going to stick to React 16 for a while, they can consciously disable that option.

With React 17+ the rule should emit a hard error when defaultProps on FC is used.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

@FredyC it's not deprecated in a released version of React yet; it's just merged to master.

@danielkcz
Copy link

And why does that matter? Obviously, the React team is already decided to deprecate it. By delaying it here you are only increasing the number of users who will have to refactor later because by default they will be forced to use defaultProps on FC. It should at least inform them about the existence of that option so they can decide.

Btw, don't forget that most users are probably using not ejected CRA apps. They will have no way to enable that option or disable the rule.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

I'm not delaying anything; I'm not going to add a breaking change for any reason - and for those using tools that rely on defaultProps - like storybook annotations, etc - silently no longer warning on these could break them.

This may not be your use case, but that doesn't mean I'm going to break it.

@danielkcz
Copy link

danielkcz commented Jul 30, 2019

What are you talking about? I am not suggesting to be forbidding to use defaultProps. They just shouldn't be required for FC anymore. If someone wants to use them, the rule could just WARN about future deprecation, but that's it. I don't even insist on that warning, but the requirement to use something that's about to be deprecated is just wrong.

@nathggns
Copy link

nathggns commented Jul 30, 2019

It seems like the happy medium is the following:

  • Add an optional no-fc-default-props rule that warns on the use of defaultProps on functional components.
  • Add the option to require-default-props to not warn when missing defaultProps on functional components.
  • Add no-fc-default-props to recommended when the change deprecating defaultProps on functional components lands in a public release
  • Make a new rule that is similar to require-default-props but for functional components & default arguments (require-fc-default-args? probably a better name for this, naming isn't my strong suit)

While some of us including @FredyC & I may like to go further than this, if @ljharb can agree to this bit of work being done now (by pull request or by a core maintainer) it might be worth starting work on what we can agree on rather than letting "perfect" (from our perspective) be the enemy of good.

@ljharb can you confirm that this is a path you'd be supportive of?

@danielkcz

This comment has been minimized.

@nathggns

This comment has been minimized.

@danielkcz

This comment has been minimized.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

I’m going to continue using the term SFC as long as the wider community does; the react team’s naming preference doesn’t constrain anyone else.

@FredyC the issue is that for some use cases, merely omitting defaultProps on an SFC will break things, because tooling requires it be present. That tooling certainly will have to adapt to lacking this information as React releases the deprecation, but until that time, omitting the defaultProps on a single component will break people.

@nathggns that plan is exactly what i was suggesting; except that nothing can be added to recommended without a breaking change, so we won’t be doing that. I’d be comfortable enabling the “don’t warn on missing default props on SFCs” option in the recommended config, however, since that warns less, and anyone depending on airbnb or on every component having defaultProps will not be affected by that.

Let’s do each thing in a separate PR, and naming bikesheds can happen there.

@danielkcz
Copy link

Oh man, I don't know. It seems like I am either explaining it badly or you are not reading what am I saying.

Let's be practical. If someone uses tooling that relies on defaultProps, they can keep using it. But has to be the user's choice. The rule shouldn't force everyone into doing something that's going to be deprecated. That's just unnecessary stalling.

I’m going to continue using the term SFC as long as the wider community does; the react to team’s naming preference doesn’t constrain anyone else.

So you are going to name rules with sfc and later change it to fc once the trend catches up? How is that a good approach? I don't know why would you be fighting against the official recommendation. It's obvious that React team cannot enforce that, but from a logical standpoint where we don't longer have stateless components, it's wrong.

I agree we should discuss further approaches in separate issues/PRs

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

That user is making that choice by using the current rule in master. Silently taking away their choice by defaulting them to a permissive mode is unacceptable.

The hooks have state, but the hooks aren’t the component - imo they’re still forever stateless.

@danielkcz
Copy link

danielkcz commented Jul 30, 2019

That user is making that choice by using the current rule in master. Silently taking away their choice by defaulting them to a permissive mode is unacceptable.

There is a problem in that logic. What if you have class components which still needs defaultProps but you also have FC where it would be misleading to have defaultProps enforced. That's why I am suggesting to ease up on the rule for FC components so you still can use the rule for class ones without being constraint toward FC.

Ultimately, this whole rule should be deprecated and there should be separate ones for class and FC, but that's surely a question of some semi-distant future.

The hooks have state, but the hooks aren’t the component - imo they’re still forever stateless.

Uh, what? :) Hooks are not components, that's true, but hooks are used in components thus making them stateful and no longer stateless. Have you ever used hooks seriously? Cannot imagine what would you say something like that 😆

@j-f1

This comment has been minimized.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

@FredyC it's not misleading if you are using tools that break when an SFC lacks defaultProps, as some people are doing now.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

As for SFCs, they were SFCs - stateless - even if they closed over variables, giving them state - the components are not stateful, they just might close over state. In the case of hooks, the hook is doing the same thing.

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

No branches or pull requests

10 participants