Skip to content

Instantly share code, notes, and snippets.

@sijad
Last active June 17, 2018 13:51
Show Gist options
  • Save sijad/44a8527d20aab66b2939a6b10e55793e to your computer and use it in GitHub Desktop.
Save sijad/44a8527d20aab66b2939a6b10e55793e to your computer and use it in GitHub Desktop.

use a state managmer for storing data

Redux or MobX

use react eslint

most important rules that I can think of:

  • react/jsx-no-bind (it gonna bost performance to another level)
  • react/prefer-stateless-function (for performance)
  • eact/no-multi-comp
  • react/prop-types (maybe, with typescript doesn't make much sense I guess)
  • react/jsx-handler-names
  • react/destructuring-assignment
  • react/forbid-component-props (maybe)
  • react/jsx-filename-extension (maybe)

more rules:

https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules

compute refrences

this'll be optimize performance, there's might be an eslint rule for this

bad:

class myComponent {
  computeObject() {
    retrun {
      a: 1,
      b: 2,
    }; // it'll re-create a new object each time
  }
  
  render() {
    const myArray = [1,2,3,4,5,6,7,8]; // it'll re-create a new array with a different refrence
    const myObject = this.computeObject();
    retrun (
      <MyOtherComponent
        myArray={myArray}
        myObject={myObject}
      />
    );
  }
}

good:

class myComponent {
  computeObject() {
    if (!this.myObject) {
      this.myObject = {
        a: 1,
        b: 2,
      };
    }
    
    return this.myObject;
  }
  
  render() {
    const myObject = this.computeObject();
    retrun (
      <MyOtherComponent
        myArray={myArray}
        myObject={myObject}
      />
    );
  }
}

const myArray = [1,2,3,4,5,6,7,8];

somthing like https://github.com/alexreardon/memoize-one can become handy.

use decorations

decorations can become very handy in some cases, for example:

import {
  get,
  put,
} from '../api';

@get('users/1')
@get('users/2', {
  name: 'user2', // prop name
})
@put()
class myComponent {

  handleEditUser(data) {
    this.props.put('users/1', data);
  }

  render() {
    if (this.props.data.loading || this.props.user2.loading) {
      retrun (
        <Loading/>
      );      
    }
    
    const {
      data: {
        user,
      },
      user2: {
        secondUser: user,
      },
    } = this.props;
    
    retrun (
      <ShowUsers
        firstUser={user}
        secondUser={secondUser}
      />
    );
  }
}

I think decorations can be useful for api call or even forms (e.g. @form({ fields, options }))

@tobyzerner
Copy link

Nice!
In your "compute references" example, maybe myArray and myObject should be set as state on the component instance?

@sijad
Copy link
Author

sijad commented Jun 16, 2018

@tobscure in most cases yes, in that particular example I just wanted to show it's better to minimize computations in render() as much as possible and avoid recreating objects and arrays props inside render() to prevent re-rendering:

bad:

render() {
  const {
    color1,
    color2,
    color3,
  } = this.props;

  const {
    stateColor,
  } = this.state;

  // each time render() get called a new array will create which may results a new dom re-render.
  // specially if it's not a pure component.
  const colors = [color1, color2, color3, stateColor];

  <ShowColors
    colors={colors}
  />
}

good:

import memoizeOne from 'memoize-one';

const createColors = (...colors) => [...colors];
const memoizedColors = memoizeOne(createColors);

render() {
  const {
    color1,
    color2,
    color3,
  } = this.props;

  const {
    stateColor,
  } = this.state;

  // memoizedColors will return last computed array if arguments are same as last call.
  const colors = memoizedColors(color1, color2, color3, stateColor);

  <ShowColors
    colors={colors}
  />
}

I might be wrong, but as I can recall when React want to re-render a component (e.g. when its parent props has been changed), React will do deep equal check (for normal components) to check if props has been changed only if the props reference has been changed, I guess it's something like this:

shouldWeReRender(oldColors, newColors) {
  if (oldColors !== newColors) { // like comparing two array e.g. [] === [] always results false
     if (!areDeepEqual(oldColors, newColors) === true) { // we can avoid this
		return true;
     }
  }
  
  return false; // props are equal, no re-render needed.
}

in second example we'll avoid a areDeepEqual() (which affects performance, specially in case of a component with lot's of props) because memoizedColors return same array each time, hence oldColors !== newColors --> false

on the other hand if we pass a new reference to a pure component it'll results a re-render, because pure components are only do a shallow comparison (it will do not call any areDeepEqual() on objects and arrays, only a simple ===), so it will gonna results re-rendering.

@sijad
Copy link
Author

sijad commented Jun 16, 2018

according to this article I'm wrong, React do not call any deepEqual:

Component on the other hand won’t compare current props and state to next out of the box. Thus, the component will re-render by default whenever shouldComponentUpdate is called.

but according to that article it's still a bad idea to re-create objects and array in render():

if you’re creating new functions, objects, or arrays in the render method you’re (probably) doing it wrong.

@sijad
Copy link
Author

sijad commented Jun 16, 2018

and also I forgot to mention, when you use something like Redux probably never gonna need to store data in the state, but I'm not sure if it'll limit the extensibility or not (Flarum extensions might need to manipulate the reducers or even it might make things a little hard for new comers). I'm not sure.

@sijad
Copy link
Author

sijad commented Jun 16, 2018

Context is also an alternative to Redux but I never used it, it might be easier to use it instead of Redux for storing data (but not for local states).

@sijad
Copy link
Author

sijad commented Jun 17, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment