-
Notifications
You must be signed in to change notification settings - Fork 73
[React] Updated some old rules #183
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
Open
damfinkel
wants to merge
3
commits into
master
Choose a base branch
from
update-react-styleguide
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -37,62 +37,46 @@ src | |||||
└───app | ||||||
│ │ | ||||||
│ └───components | ||||||
│ │ └───atoms # Can't be broken down into smaller things | ||||||
│ │ | └───Input | ||||||
│ │ | └───Text | ||||||
│ │ | └───Button | ||||||
│ │ | └───etc | ||||||
│ │ └───molecules # Two or more atoms | ||||||
│ │ | └───FormInput | ||||||
│ │ | └───SearchBar | ||||||
│ │ | └───Table | ||||||
│ │ | └───etc | ||||||
│ │ └───organisms # Two or more molecules | ||||||
│ │ └───LoginForm | ||||||
│ │ └───UserTable | ||||||
│ │ └───etc | ||||||
│ | └───FormInput | ||||||
│ | └───SearchBar | ||||||
│ | └───Table | ||||||
│ | └───etc | ||||||
| | | ||||||
│ └───screens | ||||||
│ └───MyScreenComponent | ||||||
│ └───assets # Screen specific app assets | ||||||
│ └───reducer | ||||||
│ | actions.js | ||||||
│ | reducer.js | ||||||
│ | selectors.js | ||||||
│ | effects.js | ||||||
│ └───context | ||||||
| | index.ts | ||||||
│ | actions.ts | ||||||
│ | reducer.ts | ||||||
│ └───components # Screen specific components | ||||||
│ | constants.js | ||||||
│ | i18n.js | ||||||
│ | index.js | ||||||
│ | layout.js | ||||||
│ | constants.ts | ||||||
│ | i18n.ts | ||||||
│ | index.tsx | ||||||
│ | styles.scss | ||||||
│ | utils.js | ||||||
│ | utils.ts | ||||||
│ | ||||||
└───assets # General app assets | ||||||
└───config | ||||||
| api.js | ||||||
| i18n.js | ||||||
| api.ts | ||||||
| i18n.ts | ||||||
└───constants | ||||||
└───redux | ||||||
│ | store.js | ||||||
│ └───myReducer | ||||||
│ | actions.js | ||||||
│ | reducer.js | ||||||
│ | selectors.js | ||||||
│ | effects.js | ||||||
│ | ||||||
└───propTypes | ||||||
│ | Model1.js | ||||||
│ │ Model2.js | ||||||
└───types # Custom global TypeScript classes | ||||||
└───contexts # Global contexts | ||||||
│ └───Auth | ||||||
│ | index.ts | ||||||
| | reducer.ts | ||||||
| | actions.ts | ||||||
│ | ||||||
└───scss | ||||||
└───services | ||||||
│ │ serializers.js | ||||||
│ │ serializers.ts | ||||||
│ └───Model | ||||||
│ | ModelService.js | ||||||
│ | serializers.js | ||||||
│ | ModelService.ts | ||||||
│ | serializers.ts | ||||||
│ | ||||||
└───utils | ||||||
│ index.js | ||||||
│ index.tsx | ||||||
``` | ||||||
|
||||||
## Class vs `React.createClass` vs stateless | ||||||
|
@@ -175,18 +159,18 @@ src | |||||
|
||||||
## Naming | ||||||
|
||||||
- **Extensions**: Use `.js` extension for React components. | ||||||
- **Filename**: For services use PascalCase. E.g., `ReservationCard.js` or a folder with the service name and `index.js` as filename. For React components, there must be a folder in PascalCase with its name and the component file should be `index.js` (and optionally `layout.js` if you're using [Smart/Dumb components](https://medium.com/@thejasonfile/dumb-components-and-smart-components-e7b33a698d43) | ||||||
- **Extensions**: Use `.ts` extension for React components. | ||||||
- **Filename**: For services use PascalCase. E.g., `ReservationCard.ts` or a folder with the service name and `index.tsx` as filename. For React components, there must be a folder in PascalCase with its name and the component file should be `index.tsx` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- **Reference Naming**: Use PascalCase for React components and camelCase for their associated elements. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) | ||||||
|
||||||
```jsx | ||||||
// bad | ||||||
import myService from './MyService'; | ||||||
import myComponent from './MyComponent'; | ||||||
import myComponent from './MyComponent/index.tsx'; | ||||||
|
||||||
// good | ||||||
import MyService from './MyService'; # webpack infers index.js | ||||||
import MyComponent from './MyComponent'; # webpack infers index.js | ||||||
import MyService from './MyService'; # webpack infers index.tsx | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
import MyComponent from './MyComponent'; # webpack infers index.tsx | ||||||
|
||||||
// bad | ||||||
const MyComponent = <MyComponent />; | ||||||
|
@@ -196,26 +180,17 @@ src | |||||
``` | ||||||
- **Component Hierarchy**: | ||||||
- Component files should be inside folders that match the component's name. | ||||||
- Use index.js as the filename of a container component. Use `Container` as the suffix of the component's name. | ||||||
- Use layout.js as the filename of a layout component. Only do this if your component is becoming too big, it should be an exception, not a rule. | ||||||
- Use index.tsx as the component filename. | ||||||
|
||||||
|
||||||
```jsx | ||||||
// MyComponent/index.js | ||||||
import MyComponent from './layout' | ||||||
// MyComponent/index.tsx | ||||||
|
||||||
function MyComponentContainer() { | ||||||
function MyComponent() { | ||||||
// Do smart stuff | ||||||
|
||||||
return <MyComponent /> | ||||||
} | ||||||
|
||||||
// MyComponent/layout.js | ||||||
function MyComponent() { | ||||||
return ( | ||||||
// Some JSX | ||||||
) | ||||||
} | ||||||
``` | ||||||
|
||||||
- **Higher-order Component Naming**: Use a composite of the higher-order component's name and the passed-in component's name as the `displayName` on the generated component. For example, the higher-order component `withFoo()`, when passed a component `Bar` should produce a component with a `displayName` of `withFoo(Bar)`. | ||||||
|
@@ -270,15 +245,15 @@ src | |||||
|
||||||
```jsx | ||||||
// bad | ||||||
/* routes.js */ | ||||||
/* routes.ts */ | ||||||
const userListRoute = '/users'; | ||||||
const itemListRoute = '/items'; | ||||||
|
||||||
/* Another file */ | ||||||
import * as Routes from './routes'; | ||||||
|
||||||
// good | ||||||
/* routes.js */ | ||||||
/* routes.ts */ | ||||||
const Routes = { | ||||||
userListRoute: '/users', | ||||||
itemListRoute: '/items' | ||||||
|
@@ -405,25 +380,20 @@ src | |||||
- Always use object destructuring to explicitly get props variables in the render function of class Components: | ||||||
|
||||||
```jsx | ||||||
import MyComponent from './layout'; | ||||||
import Child from './components/Child'; | ||||||
|
||||||
// bad | ||||||
class MyComponentContainer extends Component { | ||||||
render() { | ||||||
return <MyComponent foo={this.props.foo} bar={this.props.bar} /> | ||||||
} | ||||||
function MyComponent(props) { | ||||||
return <Child foo={props.foo} bar={props.bar} /> | ||||||
} | ||||||
|
||||||
// good | ||||||
class MyComponentContainer extends Component { | ||||||
render() { | ||||||
const { foo, bar } = this.props; | ||||||
return <MyComponent foo={foo} bar={bar} /> | ||||||
} | ||||||
function MyComponent({ foo, bar }) { | ||||||
return <Child foo={foo} bar={bar} /> | ||||||
} | ||||||
``` | ||||||
|
||||||
- Always use object destructuring to explicitly get props variables in layout Components: | ||||||
- Always use object destructuring to explicitly get props variables: | ||||||
|
||||||
```jsx | ||||||
// bad | ||||||
|
@@ -472,27 +442,40 @@ src | |||||
/> | ||||||
``` | ||||||
|
||||||
- Avoid passing arrow functions in props when possible. Instead, create a reference to the function and pass that reference. | ||||||
- Only use inline arrow functions when the arrow function is simple | ||||||
- If the function is complex, define it as a const beforehand. If you are passing it to a child component. you may use `useCallback` for memoization as well. | ||||||
|
||||||
> Why? Passing arrow functions as props in render creates a new function each time the component renders, which is less performant. | ||||||
|
||||||
```jsx | ||||||
import MyComponent from './layout'; | ||||||
|
||||||
// bad | ||||||
class MyComponentContainer extends Component { | ||||||
render() { | ||||||
return <MyComponent foo={bar => bar + 1} /> | ||||||
} | ||||||
function MyComponent() { | ||||||
return <button onClick={event => { | ||||||
let baz = "Hello World"; | ||||||
console.log(event.target.value + baz) | ||||||
}} /> | ||||||
} | ||||||
|
||||||
// good | ||||||
class MyComponentContainer extends Component { | ||||||
foo = bar => bar + 1; | ||||||
function MyComponent() { | ||||||
const foo = event => { | ||||||
let baz = "Hello World"; | ||||||
console.log(event.target.value + baz) | ||||||
}; | ||||||
|
||||||
render() { | ||||||
return <MyComponent foo={this.foo} /> | ||||||
} | ||||||
return <button onClick={foo} /> | ||||||
} | ||||||
|
||||||
// better when passing it to a child component | ||||||
import Child from './components/Child'; | ||||||
|
||||||
function MyComponent() { | ||||||
const foo = useCallback(event => { | ||||||
let baz = "Hello World"; | ||||||
console.log(event.target.value + baz) | ||||||
}, []); | ||||||
|
||||||
return <Child onClick={foo} /> | ||||||
} | ||||||
``` | ||||||
|
||||||
|
@@ -667,26 +650,20 @@ src | |||||
|
||||||
```jsx | ||||||
// bad | ||||||
render() { | ||||||
return <MyComponent variant="long body" foo="bar"> | ||||||
<MyChild /> | ||||||
</MyComponent>; | ||||||
} | ||||||
return <MyComponent variant="long body" foo="bar"> | ||||||
<MyChild /> | ||||||
</MyComponent>; | ||||||
|
||||||
// good | ||||||
render() { | ||||||
return ( | ||||||
<MyComponent variant="long body" foo="bar"> | ||||||
<MyChild /> | ||||||
</MyComponent> | ||||||
); | ||||||
} | ||||||
return ( | ||||||
<MyComponent variant="long body" foo="bar"> | ||||||
<MyChild /> | ||||||
</MyComponent> | ||||||
); | ||||||
|
||||||
// good, when single line | ||||||
render() { | ||||||
const body = <div>hello</div>; | ||||||
return <MyComponent>{body}</MyComponent>; | ||||||
} | ||||||
const body = <div>hello</div>; | ||||||
return <MyComponent>{body}</MyComponent>; | ||||||
``` | ||||||
|
||||||
## Tags | ||||||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be
.tsx
in most cases.