Blog

  • React Apollo - Auto Refetch

    Apollo made react fectching and updating data much more easy and simple.

    To enable auto-refetch data we just need to define a pollInterval option :

    options: { pollInterval: 20000 }

    If you use a function to compute options from props, all of these options will be automatically recalculated whenever the props change.

     

    Example :

    export default graphql(UserListQueries, {

    name: 'userListQueries',

    options: { pollInterval: process.env.REACT_APP_REFETCH_USERS_INTERVAL },

    })(UserListPage)

     

    https://github.com/helabenkhalfallah/react-apollo-redux-graphql


    Read More :

    https://www.apollographql.com/docs/react/basics/queries.html#graphql-query-options

     

  • How to create a graphql-server

     

    You can find the source code here : 

    https://github.com/helabenkhalfallah/graphql-server

     

    # graphql-server template

    1. install dependencies : 
    npm install graphql express express-graphql --save

    2. configure lint :
    npm install eslint --save-dev
    ./node_modules/.bin/eslint --init

    3. add a /server/server.js file
    in this file we will configure our gql server.
    we start by configure a simple express server

    ```
    //express config 
    const express = require('express')
    const expressGraphQL = require('express-graphql')

    // Create an express instance
    const app = express()

    // Connect with graphql and the graphiql panel
    const gqlPath = process.env.GRAPHQL_APP_PATH || '/graphql'
    console.log('gqlPath : ', gqlPath)
    app.use(gqlPath, expressGraphQL({
      graphiql: true
    }))

    // Start server
    const portNumber = process.env.GRAPHQL_APP_PORT || 4000
    console.log('portNumber : ', portNumber)
    app.listen(portNumber, () => {
      console.log('Server is running...')
    })
    ```

    4. configure dotenv :
    npm install dotenv --save
    in index.js file and before any load :

    ```
    //dot env configuration
    var dotenv = require('dotenv')
    dotenv.load()
    console.log('Your environment variable GRAPHQL_APP_PATH has the value: ', process.env.GRAPHQL_APP_PATH)

    //launch server after loading env var
    require('./server/server.js')
    ```

    5. add cors, mongoose and bluebird
    npm install cors mongoose bluebird --save

    6. add models folder which will contains all mongoose schema.
    7. add graphql folder which will contains all gql schema & CRUD.
    8. all models defined on models are exported on a single module inside index.js.
    9. all schem & CRUD defined on graphql are exported on a single module inside index.js.
    10. Define all constant inside .env file.
    11. add babel to run ES6
    npm install --save-dpev babel-cli
    npm install --save-dev babel-preset-es2015
    npm install --save-dev babel-preset-stage-0

    12. add  .babelrc

    ```
    {
      "presets": ["es2015", "stage-0"]
    }
    ```

    13. modify package.json to run with babel
    14. add nodemon so that it will automatically reload the app on everychange
    npm install --save-dev nodemon
    https://javierfernandes.gitbooks.io/rest-api-babel-express/content/nodeapp.html

    15. mongo database preparation :
    https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/
    https://stackoverflow.com/questions/2518127/how-do-i-reload-bashrc-without-logging-out-and-back-in

    16. install Robomongo
    17. customize logger file
    npm install morgan winston winston-daily-rotate-file --save
    18. Test express default route - create a route file : AppRouter.js.
    19. Test express default route - modify server.js :

    ```
    //routes
    app.use('/users', AppRouter) 
    app.use('/photos', AppRouter)

    //route index
    app.get('/', (req, res) => {
      res.send('Invalid endpoint!')
    })
    ```

    20. prepare graphql types
    21. link mongoose schema to graphql types and mongoose models using queries and mutation.
    22. modify server.js for gql endpoint :

    ```
    app.use('/graphql', cors(), expressGraphQL({
      schema: UsergqlProvider.UserQueries.UsersListQuery,
      rootValue: global,
      graphiql: true
    }))
    ```

    A single endpoint, every things is handled internaly inside gql : queries and mutations !

    23. I found an issue firstly when calling find, I got an empty result.
    I resolved this by adding collection name on mongoose models :

    ```
    let userSchema = mongoose.Schema(
      {
        first_name: String,
        last_name: String,
        birthdaye: String,
        job: String,
      },
      {
        collection: 'User'
      })
    ```

    ```
    let photoSchema = mongoose.Schema(
      {
        url: String,
        description: String,
        date: String,
      },
      {
        collection: 'Photo'
      })
    ```

  • Best practices snippets

    Replacing switch statements or multiple if with Object literals

    Bad way - switch :

    switch(type) {
    case 'coke':
      drink = 'Coke';
      break;
    case 'pepsi':
      drink = 'Pepsi';
      break;
    default:
      drink = 'Unknown drink!';
    }

     

    Bad way - multiple If :

    function getDrink (type) {
      if (type === 'coke') {
        type = 'Coke';
      } else if (type === 'pepsi') {
        type = 'Pepsi';
      } else if (type === 'mountain dew') {
        type = 'Mountain Dew';
      } else if (type === 'lemonade') {
        type = 'Lemonade';
      } else if (type === 'fanta') {
        type = 'Fanta';
      } else {
        // acts as our "default"
        type = 'Unknown drink!';
      }
      return 'You\'ve picked a ' + type;
    }

     

    Better way :

    function getDrink (type) {
      var drinks = {
        'coke': 'Coke',
        'pepsi': 'Pepsi',
        'lemonade': 'Lemonade',
        'default': 'Default item'
      };
      return 'The drink I chose was ' + (drinks[type] || drinks['default']);
    }

     

    Null, Undefined, Empty Checks Shorthand

    This  code :

    let variable1 = "";
    let variable2 = "12";
    if (variable1 !== null && variable1 !== undefined && variable1 !== "") {
      variable2 = variable1;
    }
    console.log({ variable1, variable2 });

     

    Can be replaced simply by :

    let variable1 = "";
    let variable2 = variable1 || "default";
    console.log({ variable1, variable2 });

     

    Clone an Object Using Spread

    let user = {
      first: "chris",
      last: "burgin"
    }
    let userCopy = {...user}; // new object, not by ref

  • Best practices snippets

    Never Bind in Render

    <MyComponent onClick={(id) => this.onClick(id)} />  

    Issue :

    By binding your event handlers like this, you create brand new functions every time React calls your component’s render.

    Solution : bind functions outside of render.

     

    Unnecessary render

    <Component {...props}>

    Issue :

    When container state change : all childs will been rendered (shouldComponentUpdate return true). Unnecessary render.

    Solution : pass only necessary props :

    <Component necessary={props} >

     

    Never define style in Render

    <MyComponent style={ { margin: 0 } } />  

    Issue :

    New object with margin zero is created on every render.

    New object → new reference.

    Solution : define constants outside of render :

    const myStyle = {margin : 0}; →  outside of render.
    <MyComponent style={myStyle} />

     

    PureComponent

    React.PureComponent is similar to React.Component. 
    The difference between them is that React.Component doesn’t implement shouldComponentUpdate(), but React.PureComponent implements it with a shallow prop and state comparison.

    React.PureComponent’s shouldComponentUpdate() only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences.

    Only extend PureComponent when you expect to have simple props and state.

    https://reactjs.org/docs/react-api.html#reactpurecomponent

     

    React/Redux performance tip - Dan Abramov‏ -

    Component separation can make a much bigger difference than manual shouldComponentUpdate() everywhere.

     

    Smarter updates

    shouldComponentUpdate give better control over the component’s update cycle by comparing the upcoming props and state from the current ones.

    Whatever you do inside shouldComponentUpdate, do it fast. Avoid expensive operations and go directly to shallow comparisons.

  • Functionals Components & React Component

     

    You'll find your components much easier to reuse and reason about if you divide them into two categories. I call them Container and Presentational components* but I also heard Fat and Skinny, Smart and Dumb, Stateful and Pure, Screens and Components, etc. These all are not exactly the same, but the core idea is similar.  - Dan Abramov -

     

    • Presentational Components use Functional Components, and only concerns the UI.
    • Container Components use Class Components, and concerns state and behavior.

     

    Functional or presentational Component :

    function Welcome(props) {
        return <h1>Hello, {props.name}</h1>;
    }

    Container Component :
    class Welcome extends React.Component {
       render() {
            return <h1>Hello, {this.props.name}</h1>;
       }
    }

     

    Presentational components focus on the UI rather than behavior, so it's important to avoid using state in presentational components. 

    Instead, state should be managed by higher-level "container" components, or via Flux/Redux/etc. Stateless functional components don't support state or lifecycle methods.

    Stateless functional components programmatically enforce keeping the component pure.

    You're forced to put state management where it belongs: in higher level container components.

     

    Functional Components :

    • are concerned with how things look.
    • don't have state.
    • don't have life cycle methods.
    • don't have a this.
    • are pure functions and therefore easy to test.
    • are easier to read and understand.
    • encourage you to keep in mind the best practices.
    • used for presenting static data.
    • can't handle fetching data.
    • have no dependencies on the rest of the app, such as Flux actions or stores.
    • don't specify how the data is loaded or mutated.
    • receive data and callbacks exclusively via props.
    • rarely have their own state (when they do, it's UI state rather than data).
    • are written as functional components unless they need state, lifecycle hooks, or performance optimizations.

    • Examples: Page, Sidebar, Story, UserInfo, List.

     

    React or container Component :

    • are concerned with how things work.
    • provide the data and behavior to presentational or other container components.
    • call Flux actions and provide these as callbacks to the presentational components.
    • are often stateful, as they tend to serve as data sources.
    • are usually generated using higher order components such as connect() from React Redux, createContainer() from Relay, or Container.create() from Flux Utils, rather than written by hand.
    • Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList.

     

    Benefits of This Approach :

    • better separation of concerns. You understand your app and your UI better by writing components this way.
    • better reusability. You can use the same presentational component with completely different state sources, and turn those into separate container components that can be further reused.
    • presentational components are essentially your app's "palette". You can put them on a single page and let the designer tweak all their variations without touching the app's logic. You can run screenshot regression tests on that page.
    • this forces you to extract "layout components" such as Sidebar, Page, ContextMenu and use this.props.children instead of duplicating the same markup and layout in several container components.

  • Container component structure

     

    // The ES6+ way
    class VideoContainer extends React.Component {

    //default props
    static defaultProps = {
    autoPlay: false,
    maxLoops: 10
    };

    //propsType (validation)
    static propTypes = {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired
    };

    //initial state
    state = {
    loopsRemaining: this.props.maxLoops
    };

    //construtor
    constructor(props) {
    super(props);
    this.state = { openOverlay: false };
    }

    //component life cycle
    componentWillMount() {}
    componentDidMount() {}
    componentWillReceiveProps(nextProps) {}
    shouldComponentUpdate(nextProps, nextState) {}
    componentWillUpdate(nextProps, nextState) {}
    componentDidUpdate(prevProps, prevState) {}
    componentWillUnmount() {}

    //application funtions
    handleSubmit = (e) => {
    e.preventDefault()
    this.props.videoSrc.save()
    }

    //render
    render() {
    return <div />;
    }
    }

    //redux part
    const mapStateToProps = createStructuredSelector({
    selectedFilter: makeSelectSelectedFilter(),
    sort: selectSort(),
    });

    function mapDispatchToProps(dispatch) {
    return {
    handleCloseDialog: () => dispatch(closeDialog()),
    };
    }

    //export with redux
    export default connect(mapStateToProps, mapDispatchToProps)(VideoContainer);

    //export without redux
    export default VideoContainer;

  • JS - Best Practices (let, const and var)

     

    let and const are block scoped.

    Therefore, referencing block-scoped identifiers before they are defined will produce a ReferenceError.

    console.log(x); // ReferenceError: x is not defined
    let x = 'hi';

    // const and let only exist in the blocks they are defined in.
    {
    let a = 1;
    const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

     

    Use const for all references; avoid using var.
    If you must reassign references, use let instead of var.
    let is block-scoped rather than function-scoped like var.

    Bad :

    var count = 1;
    if (true) {
    count += 1;
    }

    Good :

    // good, use the let.     
    let count = 1;
    if (true) {
         count += 1;
    }

     
    Read More :

  • Arrow functions

     

    One of the most anticipated new features in the ES6 Javascript standard was the Arrow Function Expression.

    It promises a shorter syntax than it's predecessor the Function Expression.


    Exemple : get length of each string inside an array

    let celebrities = ['Steve Jobs','Albert Einsten','Nicolas Tesla'];     

    //ES5

    const lengthES5 = celebrities.map(function(celebrity) {

      return celebrity.length;

    });

    console.log(lengthES5); //[ 10, 14, 13 ]


    //ES6
    const lengthES6 = celebrities.map(celebrity => {

      return celebrity.length;

    });

    console.log(lengthES6); //[ 10, 14, 13 ]


    //ES6 much better [ 10, 14, 13 ]
    celebrities.map(celebrity => celebrity.length);

     
    Sandbox :

    Arrow Functions lexically bind their context so this actually refers to the originating context :


    /* Function Object Context */
    var sciences = ['Physics','Chemistry','Math'];
    var searchedScience = 'Math';
    console.log(sciences)
    console.log(searchedScience)

    /* ES5 Function Object Context */
    //solution 1
    var self = this;
    this.sciences.forEach(function(science) {
        if(self.searchedScience === science){
              console.log('Founded Science 1: ', science)
        }else{
              console.log('Not Searched Science 1: ', science)
       }
    });

    //solution 2
    this.sciences.forEach(function(science) {
       if(self.searchedScience === science){
           console.log('Founded Science 2: ', science)
       }else{
           console.log('Not Searched Science 2: ', science)
       }
    }, this);

    //solution 3
    this.sciences.forEach(function(science) {
         if(self.searchedScience === science){
           console.log('Founded Science 3: ', science)
         }else{
           console.log('Not Searched Science 3: ', science)
        }
    }.bind(this));

    /* ES6 Function Object Context */
    this.sciences.forEach((science) => {
       if(this.searchedScience === science){
          console.log('ES6 Founded Science: ', science)
       }else{
          console.log('ES6 Not Searched Science: ', science)
      }
    });

  • JS - Best Practices (Importing/Exporting in ES6)

    Importing with ES6 :

    ES6 provides us with various flavors of importing :

    We can import an entire file :

    import 'underscore';


    Named imports :

    import { sumTwo, sumThree } from 'math/addition';

     

    Rename the named imports :

    import {
    sumTwo as addTwoNumbers,
    sumThree as sumThreeNumbers 
    } from 'math/addition';

     

    Import all the things (also called namespace import) :

    import * as util from 'math/addition';

     

    Import a list of values from a module :

    import * as additionUtil from 'math/addition';
    const { sumTwo, sumThree } = additionUtil;

     

    Exporting with ES6 :

    With ES6, we have various flavors of exporting :

    Named Exports :

    export let name = 'David';
    export let age = 25;​​

     

    Exporting a list :

    function sumTwo(a, b) {
        return a + b;
    }

    function sumThree(a, b, c) {
       return a + b + c;
    }

    export { sumTwo, sumThree }; 

     

    Export functions, objects and values (etc.) simply by using the export keyword :

    export function sumTwo(a, b) {
         return a + b;
    }

    export function sumThree(a, b, c) {
        return a + b + c;
    }

     

    Export default bindings :

    function sumTwo(a, b) {
        return a + b;
    }

    function sumThree(a, b, c) {
       return a + b + c;
    }

    let api = {
      sumTwo,
      sumThree
    };


    export default api;

    /* Which is the same as

    export { api as default };

    */

     

    Always use the export default method at the end of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as.

     

  • JS - Best Practices (String)

     

    Use single quotes '' for strings.

    // bad
    const name = "My String";

    // bad - template literals should contain interpolation or newlines
    let text = `This string contains "double quotes" which don't need to be escaped anymore.`;     

    // good
    const name = 'My String';

     

    .includes( )

    Instead of checking for a return value > -1 to denote string containment, we can simply use .includes() which will return a boolean:

    const string = 'food';
    const substring = 'foo';
    console.log(string.includes(substring)); // true  

     

    .repeat( )

    // String.repeat(numberOfRepetitions)
    'meow'.repeat(3); // 'meowmeowmeow'  

     

  • JS - Best Practices (Destructuring)

     

    Destructuring allows to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax.

     

    Destructuring Arrays :

    Old :

    var arr = [1, 2, 3, 4];
    var a = arr[0];
    var b = arr[1];
    var c = arr[2];
    var d = arr[3];

    ES6:

    let [a, b, c, d] = [1, 2, 3, 4];   

    console.log(a); // 1
    console.log(b); // 2

     

    Destructuring Objects :

    Old :

    var luke = { occupation: 'jedi', father: 'anakin' };       
    var occupation = luke.occupation; // 'jedi'
    var father = luke.father; // 'anakin'

    ES6:

    let luke = { occupation: 'jedi', father: 'anakin' };
    let {occupation, father} = luke;

    console.log(occupation); // 'jedi'
    console.log(father); // 'anakin'

     
    Read More:
     

  • JS - Best Practices (Shortcut Notations)

     

    Bad :

    var lunch = new Array();
    lunch[0]='Dosa';
    lunch[1]='Roti';
    lunch[2]='Rice';
    lunch[3]='what the heck is this?';

    Good :

    let lunch = [
    'Dosa',
    'Roti',
    'Rice',
    'what the heck is this?'
    ];

     

    Bad :

    if(v){

       var x = v;

    } else {

       var x =10;

    }

    Good :

    let x = v || 10;     

     

    Bad :

    var direction;
    if(x > 100){
    direction = 1;
    } else {
    direction = -1;
    }

    Good :

    let direction = (x > 100) ? 1 : -1;

     

  • JS - Best Practices (Encapsulate conditionals)

     

    Bad :

    if (fsm.state === 'fetching' && isEmpty(listNode)) {
          // ...
    }

    Correct :

    function shouldShowSpinner(fsm, listNode) {
          return fsm.state === 'fetching' && isEmpty(listNode);
    }

    if (shouldShowSpinner(fsmInstance, listNodeInstance)) {  
         // ...
    }

     

  • JS - Best Practices (Side effects)

    Accidentally modifying global variable :

    Bad :

    // Global variable referenced by following function.
    // If we had another function that used this name, now it'd be an array and it could break it.
    let name = 'Ryan McDermott';

    function splitIntoFirstAndLastName() {
        name = name.split(' ');
    }

    splitIntoFirstAndLastName();
    console.log(name); // ['Ryan', 'McDermott'];

    Correct :

    function splitIntoFirstAndLastName(name) {
         return name.split(' ');
    }

    const name = 'Ryan McDermott';
    const newName = splitIntoFirstAndLastName(name);

    console.log(name); // 'Ryan McDermott';
    console.log(newName); // ['Ryan', 'McDermott'];

     

    In JavaScript, primitives are passed by value and objects/arrays are passed by reference :

    Bad :

    //any other function that uses that cart array will be affected by this addition.
    const addItemToCart = (cart, item) => {
          cart.push({ item, date: Date.now() });
    };

    Correct :

    //clone the cart, edit it, and return the clone
    const addItemToCart = (cart, item) => {
         return [...cart, { item, date: Date.now() }];
    };

     

  • JS - Best Practices (Async Code)

     

    Use Promises whenever you can : instead of writing nested callbacks, you can have chainable Promise calls.

    Avoid :

    asyncFunc1((err, result1) => {
      asyncFunc2(result1, (err, result2) => {  
        asyncFunc3(result2, (err, result3) => {   
          console.lor(result3) })
    }) })


    Prefer :

    asyncFuncPromise1()
    .then(asyncFuncPromise2)
    .then(asyncFuncPromise3)
    .then((result) => console.log(result))
    .catch((err) => console.error(err))

     

    You can use async/await also :

    var foo = async (function() {
    var resultA = await (firstAsyncCall());
    var resultB = await (secondAsyncCallUsing(resultA));
    var resultC = await (thirdAsyncCallUsing(resultB));
           return doSomethingWith(resultC);
    });

     

  • JS - Best Practices (Functions)

    Functions should do one thing only on one level of abstraction.
    Functions should either do something (modify) or answer something (query), but not both.

    Avoid long argument list : use a single object parameter and destructuring assignment instead. It also makes handling optional parameters much easier.

    Bad :

    function getRegisteredUsers (fields, include, fromDate, toDate) {
    /* implementation */ }

    getRegisteredUsers(['firstName', 'lastName', 'email'], ['invitedUsers'], '2016-09-26', '2016-12-13')

    Correct :

    function getRegisteredUsers ({ fields, include, fromDate, toDate })
    { /* implementation */ }

    getRegisteredUsers({
    fields: ['firstName', 'lastName', 'email'],
    include: ['invitedUsers'],
    fromDate: '2016-09-26',
    toDate: '2016-12-13'
    })