From 60964a57a2a5435105cfef9aa9e8ceeb8abe48a8 Mon Sep 17 00:00:00 2001 From: damfinkel Date: Mon, 12 Aug 2019 15:53:54 -0300 Subject: [PATCH 1/2] updated some old rules --- frontend/react/style-guide.md | 202 +++++++++++++++------------------- 1 file changed, 88 insertions(+), 114 deletions(-) diff --git a/frontend/react/style-guide.md b/frontend/react/style-guide.md index b0b58557..ab45463a 100644 --- a/frontend/react/style-guide.md +++ b/frontend/react/style-guide.md @@ -25,7 +25,7 @@ - Only include one React component per file. - Always use JSX syntax. - - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. + - Do not use `React.createElement`. - Always use export default for Components. - Use `export default` for reducers, actionCreators and services. As a general rule of thumb, use `export default` for all files that have a unique object to export. @@ -37,15 +37,29 @@ src └───app │ │ │ └───components -│ │ └───baseComponents -│ │ └───Input -│ │ └───Text -│ │ └───Button +│ │ └───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 │ └───screens │ └───MyScreenComponent -│ └───assets // Screen specific app assets -│ | components +│ └───assets # Screen specific app assets +│ └───reducer +│ | actions.js +│ | reducer.js +│ | selectors.js +│ | effects.js +│ └───components # Screen specific components │ | constants.js │ | i18n.js │ | index.js @@ -53,7 +67,7 @@ src │ | styles.scss │ | utils.js │ -└───assets // General app assets +└───assets # General app assets └───config | api.js | i18n.js @@ -64,6 +78,7 @@ src │ | actions.js │ | reducer.js │ | selectors.js +│ | effects.js │ └───propTypes │ | Model1.js @@ -71,7 +86,10 @@ src │ └───scss └───services - | MyService.js +│ │ serializers.js +│ └───Model +│ | ModelService.js +│ | serializers.js │ └───utils │ index.js @@ -79,7 +97,8 @@ src ## Class vs `React.createClass` vs stateless - - If you have internal state and/or refs, prefer `class extends Component` over `React.createClass`. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) + - Avoid `React.createClass`. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) + - Prefer normal functions (not arrow functions) over classes: ```jsx // bad @@ -91,49 +110,47 @@ src }); // good - class Listing extends Component { - // ... - render() { - return
{this.state.hello}
; - } + function Listing({ hello }) { + return
{hello}
; } ``` - - And if you don't have state or refs, only for stateless components, prefer normal functions (not arrow functions) over classes: + - Prefer normal function components (not arrow functions) over `class extends Component`. Only exception is usage of `componentDidCatch` and `getDerivedStateFromError` (which have no hooks support) ```jsx // bad class Listing extends Component { + state = { foo: 1 }; + render() { - return
{this.props.hello}
; + return
{this.state.hello}
; } } - // bad (relying on function name inference is discouraged) - const Listing = ({ hello }) => ( -
{hello}
- ); + // bad + const Listing = ({ hello }) => { + const [foo, setFoo] = useState(1); + return
{hello}
; + } // good function Listing({ hello }) { + const [foo, setFoo] = useState(1); return
{hello}
; } ``` - - Avoid using helper render methods when possible. Functions that return JSX elements should probably be layout components. + - Avoid using helper render methods when possible. Functions that return JSX elements should probably be components themselves. ```jsx // bad - function TextContainer extends Component { + function TextContainer({ text }) { renderText = text => text; - render() { - return ( -
- {this.renderText('aText')} -
- ) - } + return ( +
+ {this.renderText(text)} +
+ ) } // good @@ -159,38 +176,38 @@ src ## Naming - **Extensions**: Use `.js` extension for React components. - - **Filename**: For component filenames and services use PascalCase. E.g., `ReservationCard.js`. + - **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) - **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 reservationCard from './ReservationCard'; + import myService from './MyService'; + import myComponent from './MyComponent'; // good - import ReservationCard from './ReservationCard'; + import MyService from './MyService'; # webpack infers index.js + import MyComponent from './MyComponent'; # webpack infers index.js // bad - const ReservationItem = ; + const MyComponent = ; // good - const reservationItem = ; + const myComponent = ; ``` - **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. + - 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. ```jsx // MyComponent/index.js import MyComponent from './layout' - class MyComponentContainer extends Component { + function MyComponentContainer() { // Do smart stuff - render() { - return - } + return } // MyComponent/layout.js @@ -605,69 +622,43 @@ src } ``` - - Base smart components like InputContainer, ButtonContainer, etc. if it's clear that they will want to pass all its props to it's layout component: + - HTML element wrappers (Button, Input, Image, etc.) ```jsx - import Button from './layout'; - class ButtonContainer extends Component { - // do something smart - - render() { - return