Bonus: Small Introduction to JavaScript and ES6(ECMAScript2015 - used in ReactJS and React-Native platforms. ES6 is almost fully compatible with most browsers. Check here for compatability
RNWeb Component, APIs, and Example Apps
-
JavaScript Keywords
-
General Guidelines
-
Avoiding Global Namespace
-
Declare Functions and Variables
-
Declare Expressions cleanly
-
Beware of JavaScript Type Conversion
-
Comparison Operators, Confusion, and You
-
- Modules and Grouping Components
Commenting should describe each function and purpose, but not make the function more confusing. You are describing functionality, not giving your life story. P.S. Don't be afraid of whitespace
- camelCase for identifier names (variables and functions).
- All names start with a lowercaseLetter.
Always put spaces around operators ( = + - * / ), and after commas:
var x = y + z;
var values = []; // initialize array first
values.push("Volvo", // then add values
"Saab",
"Fiat" // NOTE! No trailing Comma. Valid
); // JSON does not use trailing commas
// Trailing Commas will crash IE8
console.log(values); // result: ["Volvo", "Saab", "Fiat"]
- Put the opening bracket at the end of the first line.
- Use one space before the opening bracket.
- Put the closing bracket on a new line, without leading spaces.
- Do not end a complex statement with a semicolon.
function toCelsius(fahrenheit) {
return (5 / 9) * (fahrenheit - 32);
}
for (i = 0; i < 5; i++) {
x += i;
}
if ( time < 20 ) {
greeting = "Good day";
} else {
greeting = "Good evening";
}
General rules for object definitions:
- Place the opening bracket on the same line as the object name.
- Use colon plus one space between each property and its value.
- Use quotes around string values, not around numeric values.
- Do not add a comma after the last property-value pair.
- Place the closing bracket on a new line, without leading spaces.
- Always end an object definition with a semicolon.
var person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
- Variable and function names written as camelCase
- Constants (like PI) written in PascalCase
- Classes written in PascalCase
- Hyphens can be mistaken as subtraction attempts. Hyphens are NOT allowed in JavaScript names.
If you still want/ need more info on javascript specific content please reference the MDN Dev Guide
(Hover over a keyword to learn more about it )
break
case
catch
class
const
continue
debugger
default
delete
do
else
export
extends
finally
for
function
if
import
in
instanceof
new
return
super
switch
this
throw
try
typeof
var
void
while
with
yield
Know the difference between variable declarations. Read More
Know the appropriate scope for your variable and type of declaration you should use in JavaScript Read More
JavaScript is loosely typed Read More
When you declare a variable outside of any function, it is called a global
variable, because it is available to any other code in the current document.
When you declare a variable within a function, it is called a
local
variable, because it is available only within that function. With es6 (in React) There is also a block scope which I will discuss further in the declaring variables section.
//Initiate count
var count = 0;
// Function to increment count
function add() {
count += 1;
}
// Call add() 3 times
add();
add();
add();
// The counter is now 3
Example:
const add = (function(){
let counter = 0;
return ()=>{
counter += 1;
return counter;
}
})();
add();
-
The variable add is assigned the return value of a self-invoking function.
-
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
-
This way add becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
-
This is called a JavaScript closure. It makes it possible for a function to have "private" variables.
-
The counter is protected by the scope of the anonymous function, and can only be changed using the add function.
For More On JS Closures: Read Here
See closures in action: Finger Guessing Game on Codepen!
Looking a little more closely at how this can interact with an HTML DOM Element:
- We want to initialize a counter on the page
- We want it to increment by one without using global variables, as then the variable can be accessed outside of its scope.
A closure is a function having access to the parent scope, even after the parent function has closed
<button id="countButton" type="button">Count!</button>
<p id="number">0</p>
<script>
const countButton = document.getElementById("countButton"),
number = document.getElementById("number");
const count =
( () => {
let int = 0;
return () => {
int += 1;
return int;
}
})();
countButton.onclick = function(){
number.innerHTML = count();
}
</script>
It is a good coding practice to put all declarations at the top of each script or function.
This will:
- Give cleaner code
- Provide a single place to look for local variables
- Make it easier to avoid unwanted (implied) global variables
- Reduce the possibility of unwanted re-declarations
Types of Variable Declarations:
var
= Declares a variable, optionally initializing it to a value.
let
= Declares a block-scoped, local variable, optionally initializing it to a value.
const
= Declares a block-scoped, read-only named constant.
var vs. let Check out the following example:
var
if (true) {
var x = 5;
}
console.log("x is " + x);
// x is 5
let
if (true) {
let y = 5;
}
console.log("y is " + y);
// ReferenceError: y is not defined
Variable Hoisting:
All var
statements in a function should be placed as near to the top of the function as possible. It will be hoisted if not declared at the top, meaning JavaScript will move the declaration to the top for you, but this is not best practice and you should not rely on it.
Read More on Variable Hoisting
Always initialize a function before using it.
// Declare and initiate at the beginning
var firstName = "",
lastName = "",
price = 0,
discount = 0,
fullPrice = 0,
tax = 0,
myArray = [],
myObject = {}; // remember to end declarations with a semi-colon.
// Declare Functions:
function foo() {
firstName ="Jimmy";
console.log(firstName);
}
var baz = function() {
price = 15;
tax = 10;
discount = 5;
fullPrice = (price + tax) - discount;
console.log(fullPrice);
};
if (foo(); //result: "Jimmy";
baz(); //result: "20";
In these examples, we prefer to declare like x and NOT like y.
var x = "John";
var y = new String("John");
console.log(x === y);
/*console log = false
because x is a string and y is an object.*/
or
var x = new String("John");
var y = new String("John");
console.log(x == y)
// console logs false because you cannot compare objects.
Keep your declarations like the following:
var x1 = {}; // new object
var x2 = ""; // new string
var x3 = 0; // new number
var x4 = false; // new boolean
var x5 = []; // new array
var x6 = /()/; // new regexp
var x7 = function(){}; // new function
For example, you could define a variable as follows:
var answer = 42;
And later, you could assign the same variable a string value, for example:
answer = 'Thanks for all the fish...';
Because JavaScript is dynamically typed (read: loosely typed), this assignment does not cause an error message.
The == comparison operator always converts (to matching types) before comparison.
The === operator forces comparison of values and type
1 == 1 // true
'1' == 1 // true
1 == '1' // true
0 == false // true
0 == null // false
var object1 = {'key': 'value'}, object2 = {'key': 'value'};
object1 == object2 //false
0 == undefined // false
null == undefined // true
3 === 3 // true
3 === '3' // false
var object1 = {'key': 'value'}, object2 = {'key': 'value'};
object1 === object2 //false
These are the ES6 features that I believe to be most important / relevant to this project: Note: Some will look slightly different constructed using React's Components, but this will give you the initial idea
var materials = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
//this function returns the length of each material
console.log(materials.map(element => element.length));
// expected output: Array [8, 6, 7, 9]
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
position(x, y) {
this.x = x;
this.y = y;
}
}
class Rectangle {
constructor(width, height){
this.width = width;
this.height = height;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
get perimeter(){
return this.calcPerimeter();
}
}
Rectangle.prototype.calcPerimeter = function(){
return (this.height*2)+(this.width*2);
}
Object.defineProperty(Rectangle, 'diagonal', {get: function(){
return Math.sqrt(Math.pow(this.height, 2), Math.pow(this.width*2))}
});
const mySquare = new Rectangle(20, 20);
console.log( mySquare.area ); // 200
console.log( mySquare.calcArea() ); // 200
console.log( mySquare.perimeter ); // 80
console.log( +(mySquare.diagonal.toFixed(2)) ); // 28.28
// this formula is typically used for rectangles, but wil also work for
// squares (square formula is: diagonal = side*sqrt(2) ( or 28.28) )
// Also used + (unary operator, can also use Number()) to ensure we get an accurate number rather than
// parseInt() method which... you guessed it, makes the number a round integer.
// Fun fact: This method operates similarly to Math.floor() and will give you the nearest whole
// integer less than the current value. (in this example we get 28, antoher: parseInt(2.9999) = 2.
To declare a new instance of an object we must use the new keyword. For the example here we declared the variable 'mySquare' as a 'new Rectangle';
The get the area we can use a get method. This creates a psuedo-property 'area' that, in this case, returns the result of another function.
As you see in the last example "Object.define property" defines a new get method for our class.
this keyword is used to reference the current object. Every method / object has their own "this" keyword in reference to itself. We are declaring a constructor, which we will use to "contruct" our new object. If this was a person, maybe we would give them a constructor with a name and an age. But for this example, width and height do just fine. You can reference the "this" keyword anywhere within the class, and through external prototype methods and the definition of get methods.
in the class we declare mathods as
class Example{
constructor(){}
methodName(){
// code for this method here
return this;
}
}
Every class needs a constructor method, whether or not you need it.
If the method may be called many times, and you are in a massive workspace, with hundreds or even thousands of methods, you should get used to using prototype. These methods have access to all of the Object properties, but are not initiated with the object itself. Not only can you use prototype methods on objects YOU have declared, but also on built in Javascript objects. Since we have already seen a prototype method regarding an object we declared let's see one using the String object:
String.prototype.index0length = function(){
return this.length-1;
}
var myStr = "people love me";
console.log(myStr.length) //14
console.log(myStr.index0length()); //13
Isn't that neat! Go forth and blossom and make those objects wish they had been initiated sooner!
Technically already reviewed, but
var
Declares a variable, optionally initializing it to a value.
let
Declares a block-scoped, local variable, optionally initializing it to a value.
const
Declares a block-scoped, read-only named constant.
Both for...in
and for...of
statements iterate over something. The main difference between them is in what they iterate over.
The for...in
statement iterates over the enumerable properties of an object, in an arbitrary order.
The for...of
statement iterates over data that iterable object defines to be iterated over.
Iterating over an array:
let iterable = [10, 20, 30];
for (let i of iterable) {
i++;
console.log(i);
}
// 11
// 21
// 31
for (let i in iterable){
i++;
console.log(i);
}
// 1
// 2
// 3
(I decided to give promises more room because they rock)
Unlike old-style passed-in callbacks, a promise comes with some guarantees:
- Callbacks will never be called before the completion of the current run of the JavaScript event loop.
- Callbacks added with then() even after the success or failure of the asynchronous operation, will be called, as above.
- Multiple callbacks may be added by calling then() several times. Each callback is executed one after another, in the order in which they were inserted.
One of the great things about using promises is chaining.
const Promise = doSomething();
const Promise_2 = promise.then(successCallback, failureCallback);
In the old days, doing several asynchronous operations in a row would lead to the classic callback "hell":
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
With promises and arrow functions, promises now look like this:
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
If you would like some real examples of promises visit my codepen!
Sources:
How to Better Organize React Apps
Why React Devs should Modularize
JavaScript Module Pattern in depth
First, I want to provide an ideal / modular file base architecture:
/src
/components
/Button
/Notifications
/components
/ButtonDismiss
/images
/locales
/specs
/index.js
/styles.scss
/index.js
/styles.scss
/scenes
/Home
/components
/ButtonLike
/services
/processData
/index.js
/styles.scss
/Sign
/components
/FormField
/scenes
/Login
/Register
/locales
/specs
/index.js
/styles.scss
/services
/api
/geolocation
/session
/actions.js
/index.js
/reducer.js
/users
/actions.js
/api.js
/reducer.js
index.js
store.js
In this example, you can see how each module is grouped with similar components. Part of Modular Design:
each component, scene or service (a feature) has everything it needs to work on its own, such as its own styles, images, translations, set of actions as well as unit or integration tests.
Grouping Components based on utilization will be huge. Keeping folders, components, and modules separate and with like-content is very important.
var
= Declares a variable, optionally initializing it to a value.
let
= Declares a block-scoped, local variable, optionally initializing it to a value.
const
= Declares a block-scoped, read-only named constant.
var x1 = {}; // new object
var x2 = ""; // new string
var x3 = 0; // new number
var x4 = false; // new boolean
var x5 = []; // new array
var x6 = /()/; // new regexp
var x7 = function(){}; // new function
You can name a function
function foo() {
firstName = "Rexxar";
console.log(firstName);
}
var baz = function() {
console.log("Me Go Face, Taunt is Cheat");
}
foo();
baz();
Iterating over an array:
let iterable = [10, 20, 30];
for (let i of iterable) {
i++;
console.log(i);
}
// 11
// 21
// 31
for (let i in iterable){
i++;
console.log(i);
}
// 1
// 2
// 3
The main piece of advice you will always hear when practicing React is to NEVER set the state directly.
There is a method in React that allows you to do that called setState()
As its documentation states, redux is a predictable state container for JavaScript applications. It’s both regular library and a data-flow architecture. A lot of people think that it comes with React Native and it is just another tool of it. That’s a big misunderstanding! It’s a framework-agnostic tool that fits with React Native really well but it still can be used with almost any JavaScript library or framework like jQuery, Angular, Ember, Meteor or even vanilla JavaScript.
React does not consider direct component-to-component communication as a good practice even if it has the ability to support it. An architecture like this, is going to lead to a poorly structured source code sooner or later which will be difficult to maintain and scale. Redux offers a way to store all of the application state in just one place with global scope. Then your React Native components dispatch actions that trigger changes to the store. Components that need to “know” about those changes should be connected to Redux state.
Redux is not that different from Flux. Overall it has same architecture, but Redux is able to cut some complexity corners by using functional composition where Flux uses callback registration.
There is not a fundamental difference in Redux, but I find it makes certain abstractions easier, or at least possible to implement, that would be hard or impossible to implement in Flux.
If you made it this far, perhaps you like to read, or are maybe desperate. Anywho, here is compilation of common mistakes in JavaScript, an explanation of what went wrong, and how to fix it.
This if statement returns true (hopefully not as expected), because 10 is true:
var x = 0; // initializing x to 0
if (x = 10) // setting it's value to 10,
// not comparing!
This if statement returns false (as expected) because x is not equal to 10:
var x = 0; // initializing x to 0
if (x == 10) // Comparing it's value to 10
// or if (x === 10)
// This (===) would check type AND value.
StrictMode
currently helps with:
- Identifying components with unsafe lifecycles
- Warning about legacy string ref API usage
- Detecting unexpected side effects
- Detecting legacy context API
import React from 'react';
function ExampleApplication() {
return (
<View>
<Header />
<React.StrictMode>
<View>
<ComponentOne />
<ComponentTwo />
</View>
</React.StrictMode>
<Footer />
</View>
);
}
In the above example, strict mode checks will not be run against the Header
and Footer
components. However, ComponentOne
and ComponentTwo
, as well as all of their descendants, will have the checks.
Read More on React Strict Mode
In regular comparison, data type does not matter. This if statement returns true:
var x = 10;
var y = "10";
if (x == y)
In strict comparison, data type does matter. This if statement returns false:
var x = 10;
var y = "10";
if (x === y)
This case switch will display an alert:
var x = 10;
switch(x) {
case 10: alert("Hello");
}
This case switch will not display an alert:
var x = 10;
switch(x) {
case "10": alert("Hello");
}
Addition is about adding numbers.
Concatenation is about adding strings.
In JavaScript both operations use the same + operator.
function(){
console.log(4 + 4); // result: 8 as expected
}
Now let's take a look at if the number as been "type" changed on purpose or by accident into a string
function(){
console.log(4 + "4");
// result: 44, most likely not intended
}
It is a default JavaScript behavior to close a statement automatically at the end of a line.
Because of this, these two examples will return the same result:
function myFunction(a) {
var power = 10
return a * power
}
function myFunction(a) {
var power = 10;
return a * power;
}
Many programming languages support arrays with named indexes.
Arrays with named indexes are called associative arrays (or hashes).
JavaScript does not support arrays with named indexes.
In JavaScript, arrays use numbered indexes:
In JavaScript, objects use named indexes.
If you use a named index, when accessing an array, JavaScript will redefine the array to a standard object.
After the automatic redefinition, array methods and properties will produce undefined or incorrect results:
JavaScript objects, variables, properties, and methods can be undefined.
In addition, empty JavaScript objects can have the value null.
This can make it a little bit difficult to test if an object is empty.
You can test if an object exists by testing if the type is undefined:
if (typeof myObj === "undefined")
But you cannot test if an object is null, because this will throw an error if the object is undefined:
if (myObj === null)
To solve this problem, you must test if an object is not null, and not undefined.
You must test for not undefined BEFORE you can test for not null:
if (typeof myObj !== "undefined" && myObj !== null)
JavaScript does not create a new scope for each code block.
It is true in many programming languages, but not true in JavaScript.
This code will display the value of i (10), even OUTSIDE the for loop block:
for (var i = 0; i < 10; i++) {
// some code
}
return i;
First in the tutorial, you won't be able to get your native app up and running without adding :
export default App;
at the bottom of your App.js file. The author fails to mention this as this is a change from when the video was made.
In the tutorial videos Section 6 lecture 24, the author writes the styles for the <Header />
component like so:
const Header = () => {
const { textStyle } = styles; // This will change
return (
<View>
<Text style={styles.textStyle}>Test Application</Text>
</View>
);
};
We can just reference the style sheet in the "style" tag itself without the extra step of declaring it a const. This is how our new app begins, and this is how we should continue to code our projects.
const Header = () => {
return (
<View> // notice no const AND just appending
// styles.customStyle
<Text style={styles.textStyle}>Test Application</Text>
</View>
);
};
App.js
import React, { Component } from 'react';
import './App.css'; // note you can use external CSS files with ReactJS
import Header from './Header'; // importing from another file in the same folder
import Button from './Button';
class App extends Component {
render() {
return (
<div className="App">
<Header name="Student!" /> // Once you import, you can use these as Element Tags! Awesome!
<Button name="Click me!" /> // notice the _name=""_ part of the element. This is where things get interesting
</div> // check out Header.js file below to understand why _name=""_ is there.
);
}
}
export default App;
Header.js
import React, { Component } from 'react';
class Header extends React.Component {
render() {
return <h1>Welcome, {this.props.name}</h1>; // THIS is where the _name=""_ property comes from. we can *name* it anything.
} // it could be this.props.title and in the App.js we would call _title=""_ instead
} // although it just looks like a css selector, we can do MUCH more with it.
export default Header;
We do this so that our Components become reusable. We can change the HEADING element's properties from App.js, however we are able to keep reusing the same component multiple times in any number of different applications.
Reusing components becomes a much more integral part of our applications when they begin to get large. Reusing components ensures they will behave in exactly the same way, no matter where you put them.
For example: You could have multiple buttons on your site with this code:
Button.js
import React, { Component } from 'react';
class Button extends React.Component {
render() {
return <button>{this.props.name}</button>;
}
}
export default Button;
With this example, we can reuse the same Button component multiple times from our App.js file, but only change what the button says. This is useful if you have multiple buttons on your site used for logging in, subscribing to newsletters, or just navigating users around your page.
That about wraps up all the quirks of JavaScript and es6 syntax that I believe will be relevant to the application. Hopefully this sort of guide can serve as a first place to search for answers and give good enough resources to grasp the concepts.
I will continue updating this project with more information as I progress through the app tutorial
Thanks! -Ronnie Forcier