SaltyCrane Blog — Notes on JavaScript and web development

Some ES6+ features used in React development

The newest versions of JavaScript, ES2015 (ES6), ES2016 (ES7), ES2017 and beyond have many features that can be used today via Babel. Here are a few features I've used in React development.

Arrow functions (ES2015)

Arrow functions provide a shorthand syntax for defining functions. They also do not bind a this context so this from the lexical scope is used instead. If no curly braces are used, the value after the arrow is returned. There are other subtleties (e.g. hoisting and naming) associated with function expressions vs. function declarations. I like using arrow functions in blog posts for brevity, but I haven't decided if I like them in all circumstances yet. More information: Arrow Functions - YDKJS: ES6 & Beyond, Arrow functions - Exploring ES6, and Arrow This | getiblog for an explanation about this.

Here is a stateless React component defined using an arrow function:

const App = () => (
  <div>
    <PageBehindModals />
    <ChainedModals modalList={[ModalName, ModalPhone]} />
  </div>
);

Without arrow functions, it could be written as:

function App() {
  return (
    <div>
      <PageBehindModals />
      <ChainedModals modalList={[ModalName, ModalPhone]} />
    </div>
  );
}

Destructuring (ES2015)

The shorthand destructuring shown assigns properties of an object to variables of the same name. There is also a longhand syntax that allows you to assign to variables of different names. Destructuring works with nested objects, with arrays, and can be used in variable declarations, function return values and function arguments. More information: Destructuring - YDKJS: ES6 & Beyond

Here is an example destructuring the objects this.props and this.state:

class ChainedModals extends Component {
  render() {
    const { modalList } = this.props;
    const { currIndex, showModal } = this.state;
    // ..
  }
}

Without destructuring, it could be written as:

class ChainedModals extends Component {
  render() {
    const modalList = this.props.modalList;
    const currIndex = this.state.currIndex;
    const showModal = this.state.showModal;
    // ..
  }
}

Destructuring function arguments (ES2015)

Destructuring can be applied to function arguments that are objects or arrays. More information: Destructuring Parameters - YDKJS: ES6 & Beyond

This function expects a single object as an argument and it is destructured into onClickNext and step.

function ModalName({ onClickNext, step }) {
  return (
    <div>
      <h1>Step {step} - Name</h1>
      <Button onClick={onClickNext}>Next</Button>
    </div>
  );
}

Without destructuring, it could be written as:

function ModalName(props) {
  var onClickNext = props.onClickNext;
  var step = props.step;

  return (
    <div>
      <h1>Step {step} - Name</h1>
      <Button onClick={onClickNext}>Next</Button>
    </div>
  );
}

Nested destructuring (ES2015)

Destructuring also applies to objects nested in objects. More information: Nested Destructuring - YDKJS: ES6 & Beyond

Here is an example destructuring the nested props object:

function setIndexFromRoute(props) {
  const { modalList, location: { pathname } } = props;
  // ..
}

Without destructuring, it could be written as:

function setIndexFromRoute(props) {
  const modalList = props.modalList;
  const pathname = props.location.pathname;
  // ..
}

Object rest/spread operator (ES2018)

The ... rest operator gathers the rest of the items in the props object argument and puts them in the variable rest. The ... in the JSX is actually JSX syntax for spreading the props in the the rest object into individual props. More information: Object Rest/Spread Properties ECMAScript proposal, Objects Properties and ... - YDKJS: ES6 & Beyond, Using Object Spread Operator - Redux documentation, and JSX Spread Attributes - React documentation.

The object rest/spread operator is currently at stage 3 in the approval process so the earliest release would be ES2018. Note there is a rest/spread operator for arrays in ES2015.

function ModalName({ onClick, ...rest }) {
  return (
    <Modal {...rest}>
      <Button onClick={onClick}>Next</Button>
    </Modal>
  );
}

If only onClick, show, and backdrop props are passed to ModalName, it could be written like this. Using the rest and spread operators are useful when the properties are variable or unknown.

function ModalName(props) {
  var onClick = props.onClick;
  var show = props.show;
  var backdrop = props.backdrop;

  return (
    <Modal show={show} backdrop={backdrop}>
      <Button onClick={onClick}>Next</Button>
    </Modal>
  );
}
Object spread example

Here is an example using the object spread operator to merge 2 objects into a new object:

const initialState = {
  modalList: ["/name", "/phone", "/done"],
  currIndex: null,
  formData: {
    name: "Servur",
    phone: null,
  },
};

function handleRouteChange(state = initialState, pathname) {
  const index = state.modalList.findIndex(path => path === pathname);
  return { ...state, currIndex: index };
}

Here is how it could be done using Object.assign (ES2015):

function handleRouteChange(state = initialState, pathname) {
  const index = state.modalList.findIndex(path => path === pathname);
  return Object.assign({}, state, { currIndex: index });
}

Doing it using ES5 is much harder.

Concise properties (ES2015)

See Concise Properties - YDKJS: ES6 & Beyond

Here is an example using ES2105 concise properties:

const a = 1;
const b = 2;
const c = { a, b };

It could be written in ES5 without concise properties as:

var a = 1;
var b = 2;
var c = { a: a, b: b };

Array#includes (ES2016)

See Array#includes - YDKJS: ES6 & Beyond

Here is an example testing whether a value is included in an array using ES2016 Array#includes:

const selectedRows = [1, 2, 3];
const isSelected = selectedRows.includes(rowId);

Here is how it could be written using ES5:

var selectedRows = [1, 2, 3];
var isSelected = selectedRows.indexOf(rowId) >= 0;

Template literals (ES2015)

Template literals provide support for string interpolation. Variables and arbitrary expressions may be substituted into the string. More information: Template Literals - YDKJS: ES6 & Beyond

Here is an example using template literals:

const host = "api.github.com";
const url = `https://${host}/search/code`;

Here is how it could be written without template literals in ES5:

var host = "api.github.com";
var url = "https://" + host + "/search/code";

See also

Comments


#1 Vadorequest commented on :

Very interesting, I knew about the rest operator but the destructuring is quite new and challenging. Thanks a lot for the links to YDKJS, now I feel like a beginner in JS after learning that many things there and only read about 10% of the chapter 2.

disqus:3074019289


#2 Eliot commented on :

Thanks for your comment. I agree there is a lot to learn in YDKJS.

disqus:3074969867


#3 Sas commented on :

I love this man. Good job

disqus:3153739144


#4 Macrtur commented on :

Really great explanation of the key advantages, I think taking advantage of destructuring increases a lot code readability. Thanks for sharing it

disqus:3428341241