ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

react-style-guide.md (5704B)


      1 ## React Style Guide
      2 
      3 > This style guide comes as an addition to [Airbnb React/JSX Guide](https://github.com/airbnb/javascript/tree/master/react).
      4 > Feel free to modify it to suit your project's needs. 
      5 
      6 ### Table of Contents
      7 
      8 * [Separate folder per UI component](#separate-folder-per-ui-component)
      9 * [Prefer using functional components](#prefer-using-functional-components)
     10 * [Use CSS Modules](#use-css-modules)
     11 * [Use higher-order components](#use-higher-order-components)
     12 
     13 ### Separate folder per UI component
     14 
     15 * Place each major UI component along with its resources in a separate folder<br>
     16   This will make it easier to find related resources for any particular UI
     17   element (CSS, images, unit tests, localization files etc.). Removing such
     18   components during refactorings should also be easy.
     19 * Avoid having CSS, images and other resource files shared between multiple components.<br>
     20   This will make your code more maintainable, easy to refactor.
     21 * Add `package.json` file into each component's folder.<br>
     22   This will allow to easily reference such components from other places in
     23   your code.<br>
     24   Use `import Nav from '../Navigation'` instead of `import Nav from '../Navigation/Navigation.js'`
     25 
     26 ```
     27 /components/Navigation/icon.svg
     28 /components/Navigation/Navigation.css
     29 /components/Navigation/Navigation.js
     30 /components/Navigation/Navigation.test.js
     31 /components/Navigation/Navigation.ru-RU.css
     32 /components/Navigation/package.json
     33 ```
     34 
     35 ```
     36 // components/Navigation/package.json 
     37 {
     38   "name:": "Navigation",
     39   "main": "./Navigation.js"
     40 }
     41 ```
     42 
     43 For more information google for [component-based UI development](https://google.com/search?q=component-based+ui+development).
     44 
     45 ### Prefer using functional components
     46 
     47 * Prefer using stateless functional components whenever possible.<br>
     48   Components that don't use state are better to be written as simple pure functions.
     49 
     50 ```jsx
     51 // Bad
     52 class Navigation extends Component {
     53   static propTypes = { items: PropTypes.array.isRequired };
     54   render() {
     55     return <nav><ul>{this.props.items.map(x => <li>{x.text}</li>)}</ul></nav>;
     56   }
     57 }
     58 
     59 // Better
     60 function Navigation({ items }) {
     61   return (
     62     <nav><ul>{items.map(x => <li>{x.text}</li>)}</ul></nav>;
     63   );
     64 }
     65 Navigation.propTypes = { items: PropTypes.array.isRequired };
     66 ```
     67 
     68 ### Use CSS Modules
     69 
     70 * Use CSS Modules<br>
     71   This will allow using short CSS class names and at the same time avoid conflicts.
     72 * Keep CSS simple and declarative. Avoid loops, mixins etc.
     73 * Feel free to use variables in CSS via [precss](https://github.com/jonathantneal/precss) plugin for [PostCSS](https://github.com/postcss/postcss)
     74 * Prefer CSS class selectors instead of element and `id` selectors (see [BEM](https://bem.info/))
     75 * Avoid nested CSS selectors (see [BEM](https://bem.info/))
     76 * When in doubt, use `.root { }` class name for the root elements of your components
     77 
     78 ```scss
     79 // Navigation.scss
     80 @import '../variables.scss';
     81 
     82 .root {
     83   width: 300px;
     84 }
     85 
     86 .items {
     87   margin: 0;
     88   padding: 0;
     89   list-style-type: none;
     90   text-align: center;
     91 }
     92 
     93 .item {
     94   display: inline-block;
     95   vertical-align: top;
     96 }
     97 
     98 .link {
     99   display: block;
    100   padding: 0 25px;
    101   outline: 0;
    102   border: 0;
    103   color: $default-color;
    104   text-decoration: none;
    105   line-height: 25px;
    106   transition: background-color .3s ease;
    107 
    108   &,
    109   .items:hover & {
    110     background: $default-bg-color;
    111   }
    112 
    113   .selected,
    114   .items:hover &:hover {
    115     background: $active-bg-color;
    116   }
    117 }
    118 ```
    119 
    120 ```jsx
    121 // Navigation.js
    122 import React, { PropTypes } from 'react';
    123 import withStyles from 'isomorphic-style-loader/lib/withStyles';
    124 import s from './Navigation.scss';
    125 
    126 function Navigation() {
    127   return (
    128     <nav className={`${s.root} ${this.props.className}`}>
    129       <ul className={s.items}>
    130         <li className={`${s.item} ${s.selected}`}>
    131           <a className={s.link} href="/products">Products</a>
    132         </li>
    133         <li className={s.item}>
    134           <a className={s.link} href="/services">Services</a>
    135         </li>
    136       </ul>
    137     </nav>
    138   );
    139 }
    140 
    141 Navigation.propTypes = { className: PropTypes.string };
    142 
    143 export default withStyles(Navigation, s);
    144 ```
    145 
    146 ### Use higher-order components
    147 
    148 * Use higher-order components (HOC) to extend existing React components.<br>
    149   Here is an example:
    150 
    151 ```js
    152 // withViewport.js
    153 import React, { Component } from 'react';
    154 import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
    155 
    156 function withViewport(ComposedComponent) {
    157   return class WithViewport extends Component {
    158 
    159     state = {
    160       viewport: canUseDOM ?
    161         {width: window.innerWidth, height: window.innerHeight} :
    162         {width: 1366, height: 768} // Default size for server-side rendering
    163     };
    164 
    165     componentDidMount() {
    166       window.addEventListener('resize', this.handleResize);
    167       window.addEventListener('orientationchange', this.handleResize);
    168     }
    169 
    170     componentWillUnmount() {
    171       window.removeEventListener('resize', this.handleResize);
    172       window.removeEventListener('orientationchange', this.handleResize);
    173     }
    174 
    175     handleResize = () => {
    176       let viewport = {width: window.innerWidth, height: window.innerHeight};
    177       if (this.state.viewport.width !== viewport.width ||
    178         this.state.viewport.height !== viewport.height) {
    179         this.setState({ viewport });
    180       }
    181     };
    182 
    183     render() {
    184       return <ComposedComponent {...this.props} viewport={this.state.viewport}/>;
    185     }
    186 
    187   };
    188 };
    189 
    190 export default withViewport;
    191 ```
    192 
    193 ```js
    194 // MyComponent.js
    195 import React from 'react';
    196 import withViewport from './withViewport';
    197 
    198 class MyComponent {
    199   render() {
    200     let { width, height } = this.props.viewport;
    201     return <div>{`Viewport: ${width}x${height}`}</div>;
    202   }
    203 }
    204 
    205 export default withViewport(MyComponent);
    206 ```
    207 
    208 **[⬆ back to top](#table-of-contents)**