📌 Learning objectives:
- know what is what
- understand the (relatively) recent JavaScript syntax
- be able to design a JavaScript library
- JavaScript library for building User Interfaces (UIs)
- Facebook Open Source
- Learn Once, Write Anywhere
Documentation: https://facebook.github.io/react/
- Application architecture (pattern) for building client-side web applications
- Facebook Open Source
- Unidirectional data flow
Documentation: https://facebook.github.io/flux/
Redux is one (partial) implementation of the Flux pattern. It is now the reference and works well with React.
More about it later!
ES stands for ECMAScript and is the language specification used to implement JavaScript.
ES5 is supported by all browsers, but lacks very interesting features. It is the
JavaScript language you likely know. jQuery
used to be a great library back
then 😅
Released around 2009, this is likely the most important update to the JavaScript language.
Most of the modern browsers (e.g. Chrome) support it but to maximize compatibility, we tend to use a transpiler (e.g. Babel) to convert down to ES5.
ES2015 introduces two keywords to declare variables:
const
: can only be assigned oncelet
: can be reassigned
Both const
and let
are scoped to a block, not to a function like var
. Do
not use var
anymore, you should use const
as much as you can.
const a = 1;
let str = 'Hello, World';
// will throw a compiler error
// a = 42;
// this is ok
str = 'Nope';
if (true) {
const a = 123;
}
const foo = () => 'bar';
this.items.map(x => this.doSomethingWith(x));
const odds = evens.map(v => v + 1);
const pairs = evens.map(
v => ({ even: v, odd: v + 1 })
);
const bar = () => {
// do something ...
return 'val';
};
// arrays
const values = ['one', 'two', 'three', 'four'];
const [one, two, ...others] = values;
// objects
const props = { a: 'x', b: 'y', c: 'z' };
const { a, c } = props;
// in functions
function foo({ x }) {
console.log(x);
}
- One default export per file
- Every other import and export must be named
// import the default export
import React from 'react';
// import other named exports
import { Component, Children } from 'react';
// import default and others simultaneously
// import React, { Component, Children } from 'react';
const React = () => {};
// default export
export default React;
// named export
export const Component = () => {};
export const PI = 3.14;
// multiline strings
const multiline = `string text line 1
string text line 2`;
// interpolation <3
const val = 12;
const message = `Cost: ${val} euros`;
const alt = `this is ${val || 'undefined'}`;
Tags allow you to parse template literals with a function. Have a look at the common-tags library for examples:
import { oneLine } from 'common-tags';
oneLine`
foo
bar
baz
`
// "foo bar baz"
const sayHello = (name = 'World') => {
console.log(`Hello, ${name}!`);
};
sayHello();
sayHello('Jean');
// default value is used iif name is `undefined`
sayHello(null);
class Calculator {
constructor(value1, value2) {
this.value1 = value1;
this.value2 = value2;
}
static multiply(value1, value2) {
return value1 * value2;
}
sum() {
return this.value1 + this.value2;
}
}
const calc = new Calculator(2, 3);
console.log(calc.sum());
console.log(Calculator.multiply(2, 3));
const id = 123;
const name = 'John Doe';
const user1 = { id, name };
const user2 = { id, name: 'Babar' };
const attribute = 'color';
const style = {
[attribute]: 'white',
};
console.log(style.color);
const foo = ['a', 'b', 'c'];
const bar = ['d', 'e', 'f'];
console.log(...foo);
console.log([...foo, ...bar]);
class Foo {
static bar = 'hello';
}
console.log(Foo.bar);
const defaultStyle = {
color: 'black',
fontSize: 12,
fontWeight: 'normal',
};
const style = {
...defaultStyle,
fontWeight: 'bold',
backgroundColor: 'white',
};
console.log(style);
The purpose of async
/await
functions is to simplify the behavior of using
promises synchronously.
const printJSON = (endpoint) => {
// Promise chain
return fetch(endpoint) // return a Promise
.then(response => response.json())
.then(json => {
console.log(json);
})
.catch(error => {
console.error(error);
});
};
const printJSON = async (endpoint) => {
try {
const response = await fetch(endpoint);
const json = await response.json();
console.log(json);
} catch (error) {
console.error(error);
}
};
Let's start by creating a new project:
$ mkdir -p react/seq-utils
$ cd !$
$ git init
In a index.js
file, write a generate()
function to randomly generate DNA
sequences. This function must be written in ES2015 and exported.
A sequence has a unique identifier id
, a name
and the dna
sequence itself,
compound of letters (nucleotides):
{
id: 123456,
name: 'name of the sequence',
dna: 'ATCG...'
}
// index.js
export const generate = () => {
const nucleotides = ['A', 'T', 'C', 'G'];
const length = Math.round(Math.random() * 90) + 10;
const s = [];
for (let i = 0; i < length; i++) {
s.push(nucleotides[Math.floor(Math.random() * nucleotides.length)]);
}
return {
id: `TD${new Date().getTime()}${length}`,
name: `Sequence ${length}`,
dna: s.join(''),
};
};
Does it actually work?
Hello Jest, a powerful JavaScript testing framework:
$ npm init # accept all the default settings
$ npm install jest --save-dev
$ ./node_modules/.bin/jest
No tests found
You can also put this into your shell config to avoid typing the relative path to the tools installed via NPM:
export PATH="$PATH:./node_modules/.bin"
$ jest
// index.test.js
import { generate } from './index';
test('it generates sequences', () => {
// TODO: add assertions
});
Documentation: https://facebook.github.io/jest/
$ jest
FAIL ./index.test.js
● Test suite failed to run
/path/to/react/seq-utils/index.test.js:2
import { generate } from './index';
^^^^^^
...
$ npm i --save-dev babel-jest babel-preset-es2015 regenerator-runtime
$ echo '{ "presets": ["es2015"] }' > .babelrc
$ jest
PASS ./index.test.js
✓ it generates sequences (3ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.701s
Ran all test suites.
Edit package.json
to update the test
script entry:
"scripts": {
"test": "jest"
}
$ npm test
- Install the testing dependencies in your project
- Write a unit test for your
generate()
function
// index.test.js
import { generate } from './index';
test('it generates sequences', () => {
const seq = generate();
expect(seq.id).toBeDefined();
expect(seq.name).toBeDefined();
expect(seq.dna).toBeDefined();
});
Can we share it?
Transpilation means converting JavaScript ES2015 into JavaScript ES5 to maximize compatibility.
$ npm i --save-dev babel-cli
$ ./node_modules/.bin/babel index.js --out-dir dist/
index.js -> dist/index.js
Documentation: https://babeljs.io/
NPM scripts are custom scripts that can be run with npm run
. It is similar to
Makefile
targets, except that they are bundled in the package.json
file:
"scripts": {
"test": "jest",
"build": "babel index.js --out-dir dist/"
}
$ npm run build
- Overriding the main module in
package.json
:
{
"main": "dist/index.js",
...
}
- Create a
.npmignore
file:
$ echo "*.js\n*.tgz\n.babelrc" > .npmignore
- Create a
.gitignore
file:
$ echo 'coverage/' >> .gitignore
$ echo 'dist/' >> .gitignore
$ echo 'node_modules/' >> .gitignore
$ echo '*.tgz' >> .gitignore
4. Add a hook to automatically build the dist files:
"scripts": {
"build": ...,
"prepare": "npm run build"
}
That's it! Now we can package the library:
$ npm pack
$ tar tf seq-utils-1.0.0.tgz
package/package.json
package/dist/index.js
Follow the instructions to set your NPM author info at: https://gist.github.com/coolaj86/1318304. Then, publish:
$ npm publish ./
- Create a NPM module
In the sequel, we will use NtSeq, a
library to manipulate sequences. Let's add a createSequenceFromDNA()
function
returning a Seq
instance given a DNA sequence:
const seq = createSequenceFromDNA('ATCG');
- Require
ntseq
- Add a new exported function to your module
- Add a test case
$ ./node_modules/.bin/jest --coverage
PASS ./index.test.js
✓ it generates sequences (3ms)
✓ it returns a Seq instance from a sequence (2ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.795s, estimated 1s
Ran all test suites.
----------|---------|----------|---------|---------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
----------|---------|----------|---------|---------|----------------|
All files | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
----------|---------|----------|---------|---------|----------------|