Skip to content

Commit

Permalink
Merge 8f3dc4d into 8093565
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Wullems committed Nov 11, 2019
2 parents 8093565 + 8f3dc4d commit 48dbb08
Show file tree
Hide file tree
Showing 5 changed files with 1,154 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2754,3 +2754,4 @@ If you're still not using React 15 you can keep the old behavior by setting the
[`static-property-placement`]: docs/rules/static-property-placement.md
[`jsx-curly-newline`]: docs/rules/jsx-curly-newline.md
[`jsx-no-useless-fragment`]: docs/rules/jsx-no-useless-fragment.md
[`function-component-definition`]: docs/rules/function-component-definition.md
254 changes: 254 additions & 0 deletions docs/rules/function-component-definition.md
@@ -0,0 +1,254 @@
# Enforce a specific function type for function components (react/function-component-definition)

This option enforces a specific function type for function components.

**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line.

## Rule Details

This rule is aimed to enforce consistent function types for function components. By default it prefers function declarations for named components and function expressions for unnamed components.

The following patterns are considered warnings:

```jsx
// function expression for named component
var Component = function (props) {
return <div>{props.content}</div>
}

// arrow function for named component
var Component = (props) => {
return <div>{props.content}</div>
}

// arrow function for unnamed component
function getComponent() {
return (props) => {
return <div>{props.content}</div>
}
}
```

## Rule Options

This rule takes an options object as a second parameter where the preferred function type for components can be specified. The first property of the options object is `"namedComponents"` which can be `"function-declaration"`, `"function-expression"`, or `"arrow-function"` and has `'function-declaration'` as its default. The second property is `"unnamedComponents"` that can be either `"function-expression"` or `"arrow-function"`, and has `'function-expression'` as its default.

```js
...
"react/function-component-definition": [<enabled>, {
"namedComponents": "function-declaration"|"function-expression"|"arrow-function",
"unnamedComponents": "function-expression"|"arrow-function"
}]
...
```

The following patterns are considered warnings:

```jsx
// only function declarations for named components
// [2, { "namedComponents": "function-declaration" }]
var Component = function (props) {
return <div/>
}

var Component = (props) => {
return <div/>
}

// only function expressions for named components
// [2, { "namedComponents": "function-expression" }]
function Component (props) {
return <div/>
}

var Component = (props) => {
return <div/>
}

// only arrow functions for named components
// [2, { "namedComponents": "arrow-function" }]
function Component (props) {
return <div/>
}

var Component = function (props) {
return <div/>
}

// only function expressions for unnamed components
// [2, { "unnamedComponents": "function-expression" }]
function getComponent () {
return (props) => {
return <div/>
}
}

// only arrow functions for unnamed components
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent () {
return (props) => {
return <div/>
}
}

```

The following patterns are **not** warnings:

```jsx

// only function declarations for named components
// [2, { "namedComponents": "function-declaration" }]
function Component (props) {
return <div/>
}

// only function expressions for named components
// [2, { "namedComponents": "function-expression" }]
var Component = function (props) {
return <div/>
}

// only arrow functions for named components
// [2, { "namedComponents": "arrow-function" }]
var Component = (props) => {
return <div/>
}

// only function expressions for unnamed components
// [2, { "unnamedComponents": "function-expression" }]
function getComponent () {
return (props) => {
return <div/>
}
}

// only arrow functions for unnamed components
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent () {
return (props) => {
return <div/>
}
}

```

## Unfixable patterns

There is one unfixable pattern in javascript.

It has to do with the fact that this is valid syntax:

```js
export default function getComponent () {
return <div/>
}
```

While these are not.

```js
export default var getComponent = () => {
return <div/>
}

export default var getComponent = function () {
return <div/>
}
```

These patterns have to be manually fixed.

## Heads up typescript users

Note that the auto fixer is somewhat constrained for typescript users.

The following patterns can **not** be autofixed in typescript:

```tsx
// function expressions and arrow functions that have type annotations cannot be autofixed to function declarations
// [2, { "namedComponents": "function-declaration" }]
var Component: React.FC<Props> = function (props) {
return <div/>
}

var Component: React.FC<Props> = (props) => {
return <div/>
}

// function components with one unconstrained type parameter cannot be autofixed to arrow functions because the syntax conflicts with jsx
// [2, { "namedComponents": "arrow-function" }]
function Component<T>(props: Props<T>) {
return <div/>
}

var Component = function <T>(props: Props<T>) {
return <div/>
}

// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T>(props: Props<T>) => {
return <div/>
}
}
```

Type parameters do not produce syntax conflicts if either there are multiple type parameters or, if there is only one constrained type parameter.

The following patterns can be autofixed in typescript:

```tsx
// autofix to function expression with type annotation
// [2, { "namedComponents": "function-expression" }]
var Component: React.FC<Props> = (props) => {
return <div/>
}

// autofix to arrow function with type annotation
// [2, { "namedComponents": "function-expression" }]
var Component: React.FC<Props> = function (props) {
return <div/>
}

// autofix to named arrow function with one constrained type parameter
// [2, { "namedComponents": "arrow-function" }]
function Component<T extends {}>(props: Props<T>) {
return <div/>
}

var Component = function <T extends {}>(props: Props<T>) {
return <div/>
}

// autofix to named arrow function with multiple type parameters
// [2, { "namedComponents": "arrow-function" }]
function Component<T1, T2>(props: Props<T1, T2>) {
return <div/>
}

var Component = function <T1, T2>(props: Props<T2>) {
return <div/>
}

// autofix to unnamed arrow function with one constrained type parameter
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T extends {}> (props: Props<T>) => {
return <div/>
}
}

// autofix to unnamed arrow function with multiple type parameters
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T1, T2>(props: Props<T1, T2>) => {
return <div/>
}
}

```

## When not to use

If you are not interested in consistent types of function components.
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -15,6 +15,7 @@ const allRules = {
'forbid-elements': require('./lib/rules/forbid-elements'),
'forbid-foreign-prop-types': require('./lib/rules/forbid-foreign-prop-types'),
'forbid-prop-types': require('./lib/rules/forbid-prop-types'),
'function-component-definition': require('./lib/rules/function-component-definition'),
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'),
'jsx-child-element-spacing': require('./lib/rules/jsx-child-element-spacing'),
'jsx-closing-bracket-location': require('./lib/rules/jsx-closing-bracket-location'),
Expand Down

0 comments on commit 48dbb08

Please sign in to comment.