Javascript to know for Reactjs
okeken
Posted on August 8, 2022
Learning React js should not be that difficult if you're already comfortable with some concepts in Javascript. One of the interesting things about using reactjs is, it sharpens your javascript skills, but hey before you decide to give react js a try, do make sure to understand these javascripts concepts.
One of the mistake people make when learning a framework/library is, what it's bringing to the table. Before we get started, here're topics we will be covering. While some of this topics are not directly related to reactjs, you'll likely see them often in a react codebase. Note, most of the topics mentioned here, are es6 and es-next javascripts features.
- Let and Const
- Ternaries
- Template Literals
- Shorthand Properties
- Rest/Spread
- Destructuring
- Default Parameters
- ES Modules
- Short circuit Evaluation
- Higher Order Functions (Array Methods)
- Nulish Coalescing Operation
- Optional Chaining
- Arrow Functions
Introduction
React js is an open javascript library that enables us to be build fast, declarative and component driven web development. With react js you can build web apps, cross platform mobiles apps(react native), desktop apps (electron, node gui), progressive web apps(pwas). So learning react js is worthwhile because you can port your knowledge in building lot of stuffs.
For example if you're to do the operation below in vanilla javascript, let's say you want to fetch the list of users and display appropriate loading or errors, you would do something like this.
<button onclick='displayData'> see users </button>
<div id='users'>
</div>
<div id='loading'>
</div>
<div id='error'>
</div>
const usersUI = document.getElementById("users");
const loadingUI = document.getElementById("loading");
const errorUI = document.getElementById("error");
const apiUrl = "https://jsonplaceholder.typicode.com/users";
// fetch data from an api
const fetchData = async () => {
const res = await fetch(apiUrl);
return await res.json();
};
// display your data to the ui
const displayData = async () => {
errorUI.innerHTML = "";
loadingUI.innerHTML = "Loading...";
fetchData()
.then((users) => {
usersUI.innerHTML = users.map((item) => <p>$ {item.name}</p>);
})
.then(() => (loadingUI.innerHTML = ""))
.catch(() => {
loadingUI.innerHTML = "";
errorUI.innerHTML = "Error fetching data";
});
};
import React, {useState} from 'react'
const User = ()=>{
const [loading, setLoading] = useState=(false)
const [hasError, setHasError] = useState("")
const [users, setUser] = useState([])
const loadData = async()=>{
setLoading(true)
setHasError("")
fetch(apiUrl).then(res=> res.json() )
.then((data)=> {
setUsers(data)
})
.catch((error)=> setHasError(error))
.finally(()=>setLoading(false))
}
return (
<div>
<button onClick={loadData}> load users </button>
{loading ? "Loading..." : ""}
{!!users && users.map((user) => <p> {user.name} </p>)}
{!!hasError && "Error Fetching Data"}
</div>
) }
Look how we start from targeting the elements from the html, making the api and setting the appropriate UI from the function, what if we have up to 100 UI to update on the screen, that'll quickly turn it int a spagetti code. Compared to our react version, we set the status of our application in a html-like syntax called jsx.
Let and Const
Let and const are similar way of declaring a variable in javascript, the keyword let
indicates the variable can still be re-assigned to another value, whille with const, we're saying that's the final value
let favNumber = 7;
const LargestSea ='The Philippine Sea'
favNumber can still be re-assigned without any issue, but if you try to re-assign LargestSea
, you will get a parser error, Assignment to constant variable.
Ternaries
Ternaries are shorter way of declaring if-else statement in programming. For example, declaring a function to check if an number is even;
function isEven(input){
const even = n % 2 == 0;
if(even) {
return true
} else {
return false
}
}
this can be re-written to input % 2===0 ? true :false
the expression input % 2===0
, checks for ?
which indicates the output if the statement is truthy and :
tells what to put in the else output.
A practcal example is conditionally add className or style when performing an operation.
<div className={success?'success-item' :'item'}>
Items List
</div>
Although, you can have multiple nested ternaries, it's not considered the best pratice, because it reduces code readability.
Template Literals
Template literals are cleaner way of concatenating items in a javascript expression. it starts by declaring backticks, and followed by the $
sign and curly brackets with the intended variable to be concatenated in-between the curly brackets, it's structure looks like this, ${variable} other texts
. Take for instance,
let age = 10; you'll probably concatenate like,
const ageOutput = 'You are ' + age + ' years old'
we can do better by writing something like this in template literals, const ageOutput = `You are ${age} years old `
. Look at how clean that is. A practical exmple in react, we will extend our ternary operator example a bit, say you also have different classes in the div below, having "item-section first-section" beside the curly brackets indicates this as a string, it works perfectly without us needing to concatenate.
<div className={ $ {success?'success-item' :'item'} item-section first-section}>
Items List
</div>
Shorthand Properties
Take for example, we have a sample object,
const name = "Roy"
let user = { name:name }
we can re-write this to be let user= {name}
note, 'name' is now singular inside the object.
Rest/Spread
Rest/Spread is an es6 feature of copying, joining arrays in javascript. It starts with "..." three dots followed by what you want to join or copy.
for example if we have a sample data,
Objects
const user = {
name:'Tony',
age:12
}
const otherPropertie = {
hobby:'hiking',
bestColor:'red'
}
if we're to join this together before es6, we can use the Object.assign
method.
The Object.assign() method allows you to copy all enumerable own properties from one or more source objects to a target object, and return the target object, Object.assign(target, user, Obj2, Obj3, ...)
:
let finalMerge = Object.assign({}, user, otherProperties)
console.log(finalMerge) // { name: 'Tony', age: 12, hobby: 'hiking', bestColor: 'red' }
using the spread operator we can simple just put it this way, let finalMerge = {...user, ...otherProperties}
Arrays
Take for example you have two sample arrays;
const permissions = ['view user', 'view reports', 'download reports']
const otherPermissions = ['initiate transactions', 'delete user']
Before es6, we could do use the array concat method, const finalArray = permissions.concat(otherPermissions)
would give us something like this ['view user', 'view reports', 'download reports', initiate transactions', 'delete user']
. We can do better by using the spread operator,
const finalMerge = [...permissions, ...otherPermissions]
Destructuring
Destructuring is a way of accessing the values inside an object or array in a more cleaner and readable way.
Object Destructuring
const person ={
favNumber:'green',
name:'Mike',
cars:['mercedes', 'toyota']
}
before es6, if we want to get the individual properties in the person object, we'll first need to assign each of the properties to a varaiable;
const favNumber = person.favNumber;
const name = person.name
const cars = person.cars
with object destructuring, we could do something like below;
const { favNumber, name, cars } = person
console.log(favNumber, name, cars) // green, Mike, ['mercedes', 'toyota']
Look at how, we are able to get the values without needing to re-assign it. We can still do some somethings with object destructuring, what if we want to rename the name property on the person object immediatelty after destructuring, we can have something like this.
const {name:realName, favNumber, cars} = person,
console.log(realName) // "Mike".
What if we destructure an object and we want to give it a default value, even while we're not sure this is available yet on the object,
const {name, favNumber, cars, favFood='jollof rice' } = person
console.log(favFood) // 'jollof rice'
We can even go ahead and destructure nested objects, eg
const customer = {
name:'Tom',
mobile:"078 7070 2325",
email:tomfield@email.com,
address:{
country:'UK',
city:'East Davoch',
zipCode:AB34,
street:'33 Guildford Rd'
}
}
if we want to get the customer
country, we could destructure it,
const {address: { country } } = customer
console.log(country) // UK
in our previous topic, we talked about 'rest/spread', Let's talk more about the rest operator, most of the time, we use both interchangeably, specifically we use 'rest' to copy part or rest of an array or object.
const {cars, favNumber, ...otherObj} = person
console.log(otherObj) // {name:'Mike'}
It copies the rest of the object for us to use. Practical react example
const HeaderComponent = ({title, ...restProps})=>{
return <div {...restProps}> {title} </div>
}
we can use our HeaderComponent
like this <HeaderComponent className='my-item' />
thereby applying our 'my-item' class as if we added it manually to the component itself.
function Argument Destructuring
If we are to pass an object as argument to a function, we can destructure it out, during usage. For example
let car = {name:'Tesla', color:'red'}
function getCar({name, color}){
return `Your car is ${name} with the color ${color}`
}
In the getCar function argument, we can destructure it out, since we know what we're expecting.
Array Destructuring
Array destructuring works similarly like object destructuring. for example, let's look at the sample data below.
const users = ['John', 'Mike', 'Cole', 'Bekky']
const [a,b, ...others] =users
console.log(a,b, others) // 'John', 'Mike', ['Cole, Bekky']
Practical example in react is the useState function
import {useState} from 'react'
const [loading, setLoading] = useState(false)
Default Parameters
Default parameters allows us to set a default value for a function parameter if its missing while being called. For example;
function greetUser(username='user'){
return `Welcome ${username}, hope you bought some pizzas`
}
const greetingsOne = greetUser('Greg')
console.log(greetingsOne) // 'Welcome Greg, hope you bought some pizzas'
const greetingsTwo = greetUser()
console.log(greetingsTwo) // 'Welcome user, hope you bought some pizzas'
Note, the difference between the two greetings, in the second greeting, username returned as 'user' because that's what we passed as the default value.
ES Modules
ES Modules is the standard way Javascript handles, javascript files that exposes values needed externally from other files/places, using the export
keyword. It's worth noting, we also do have commonjs standard for many years, but the implementation of ECMAScript (a JavaScript standard meant to ensure the interoperability of web pages across different web browsers), ES module paves the way browsers parses and loads javascript files.
ES Module
person.js
export const person = {
name:'Simon',
color:'yellow'
}
user.js
import { person } from 'person.js'
console.log(person) // { name:'Simon', color:'yellow' }
We can export values in our js file in two ways, named export
and default export
, our first example in, person.js is a named export, the name you use to declare it its file must be the same name you are using to importing it, in our case, 'person' but what if we already have a variable in our file having the same name? well we can rename it with alias import {person as currentPerson } from './person.js'
we have successfully rename person to currentPerson.
import { person as currentPerson } from "./person.js";
console.log(currentPerson) // { name:'Simon', color:'yellow' }
Default Export
Default exports allows us to only expose a single value to the outside world in a js file. It is indicated by using the keyword, export default 'value'
usually at the bottom of the file or immediately after it's declaration. You can only use a default export once in a file, else, it throws a parser error;
colors.js
const colors = ['red', 'blue', 'green', 'orange']
export default colors;
views.js
import colorList from './colors.js'
console.log(colorList) // '['red', 'blue', 'green', 'orange']'
When a file is exported by default you can import it with any name you want, we could have called, 'colorList', 'colorsArray' and it will still work fine.
Short circuits
Short circuits is evaluating expression from left to right, until it is confirmed, the already evaluated conditions, is not going to affect the remaining conditions, thereby skipping unneccessary works leading to efficient processing. Short cicuits supports two operators, (&&) AND and (||) OR.
AND (&&)
true && 'Hello' -> This outputs 'Hello'
true && true && false -> This outputs 'false'
false && true -> This outputs 'false'
(true && false) && false -> This outputs 'false'
OR (||)
true || false -> This outputs true
false || 'hello' || false -> This outputs 'hello'
Pratcical react usage
import {useState, useEffect} from 'react';
const Items = ()=>{
const [loading, setLoading] = useState(false)
const [data, setData] = useState([])
async function ladData(){
const response = await (await fetch('http://apiEndPoint')).json()
setData(response)
setLoading(false)
}
useEffect(()=>{
setLoading(true)
loadData()
},[])
return (
<div>
{loading && "Loading"} // while loading is true shows 'Loading...'
{data.lengtht && data.map((item) => <p key={item.id}> {item.sampleName} </p>)}
// if data.length is truthy, ie, it's length is greater than 1 // then go
ahead to ahead to show list in the UI
</div>
) }
Be careful when using short-circuit for conditional rendering, scenarios like zero and undefined can cause weird behaviours on the UI.
for example,
const Todos = ()=>{
const list = []
return (
<div>
{list.length && list.map((todo) => <p key={todo.id}>
{todo.title} </p>)}
</div>
) }
Guess what will be displayed as the list of todos? "0". Yeah, basically javascript interpretes zero or undefined value to falsy value. One way we can solve this is typecasting the list.length
to boolean, !!list.length
or Boolean(list.length)
would have prevented this kind of error.
Higher Order Functions (Array Methods)
Higher Order Functions (HOF) are function which takes another function as an argument/parameters or returns a function.
The chances are, you've used at least once or more unknownly. Commons one's you may be using are;
- Find
- Filter
- Map
- Includes
- Reduce
other notable mentions here, some, every.
const users = [
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"lifeTimePurcahse":4000
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna@melissa.tv",
"phone": "010-692-6593 x09125",
"website": "anastasia.net",
"lifeTimePurcahse":78200
},
{
"id": 3,
"name": "Clementine Bauch",
"username": "Samantha",
"email": "Nathan@yesenia.net",
"phone": "1-463-123-4447",
"website": "ramiro.info",
"lifeTimePurcahse":600
},
{
"id": 4,
"name": "Patricia Lebsack",
"username": "Karianne",
"email": "Julianne.OConner@kory.org",
"phone": "493-170-9623 x156",
"website": "kale.biz",
"lifeTimePurcahse":10000
},
]
Find
find method takes in a function as the argument, and returns the find element that satisfies the testing function.
function Checker(item){
return item.id === 1
}
users.find(checker) // or users.find((item)=> item.id ===1) both functions returns the same output
// {
//"id": 1, "name": "Leanne Graham", "username": "Bret","email": "Sincere@april.biz",
// "phone": "1-770-736-8031 x56442", "website": "hildegard.org","lifeTimePurcahse":4000
// }
Filter
The filter method returns a new array filled with the elements that passed the test set by the callback function. It doesn't change or mutate the original array.
const userPurchases = users.filter(user => user.lifeTimePurchase > 70000)
// only user with id 2 has lifetimePurchase greater than 70,000
console.log(userPurchases)
// [ {
// "id": 2,
// "name": "Ervin Howell",
// "username": "Antonette",
// "email": "Shanna@melissa.tv",
// "phone": "010-692-6593 x09125",
// "website": "anastasia.net",
// "lifeTimePurcahse":78200
// }]
Filter will always return an array with the filtered results.
Map method
The map method returns a new array filled with items that satisfies the condition of the callback function. It also ends up changing the original array.
const userIds = users.map((user, index)=> user.id)
console.log(userIds) // [1,2,3,4]
Includes
The include method is used to check whether a given item is present in an array, it returns a boolean value, either true or false.
const userIsPresent = users.map(i=> i.id).includes(1)
console.log(userIsPresent) //true
Reduce Method
The reduce method takes in a reducer function to return a singular value,
Anatomy of the reduce method looks like below;
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
function reducerFunc(total, currVal, currIndex, arr){
// currIndex -> Current Index during iteration
// arr -> The whole
// total -> current total on each iteration
//currVal -> Current value on each iteration
return total + currVal.lifeTimePurchase
}
// we are setting zero as the initial value of total
const totalLifeTimePurchases = users.reduce(reducerFunc,0)
console.log(totalLifeTimePurchases) // 92800
Let's see a react example of Higher Order Functions;
const Users =()=>{
const currenttUserId=3
const vipUserPurchase = 10000
const raffleUserWinners = [1,4,3]
// map
const _users = users.map(user => (<p key={user.id}>
{user.username} </p>))
function reducerFunc(total, currVal){
return total + currVal.lifeTimePurchase
}
//reduce
const totalLifeTimePurchases= users.reduce(reducerFunc,0)
// find
const currentUser = users.find(user=> user.id== currentUserId)
//filter
const vipList = users.filter(user=> user.lifeTimePurchase >= vipUserPurchase)
// includes
const isRaffleWinner = users.map(user=>user.id).includes(currenttUserId)
return (
<div>
{_users}
<p>Total Purchase: {totalLifeTimePurchase} </p>
<p>current user: {currentUser.username} </p>
<h4> vip list <h4>
{
vipList.map(user=> <p key={user.id}> {user.username} </p>)
}
raffle status: {isRaffleWinner ? 'Congrats, you're a raffle winner' : 'Oops! Try again later'}
</div>)
}
Nulish Coalescing Operation
Nullish coalescing operations(??) allows us to return the right hand operand when the left side operand is null or undefined;
const a =12
const b = 50;
a ?? b // -> 12
let c;
let d =45
c ?? d // -> 45
Optional Chaining
Optional chaining(?.) allows us to access the key of an object safely or call functions when we're not sure if it'll be available or not.
let user = {
name: "Joe",
details: { age: 82 }
};
const userTown= user?.address?.town;
console.log(userTown); // undefined
const user.fullInfo?.() // undefined
Arrow Functions
Arrow function also called fat-arrow are alternative way of declaring functions in javascripts. They do behave differently in how they handle this
, they do bind to the this
execution context of their parent class/object. but since the current convention in react is hooks, rather than es6 classes, we do not need to bother much about this
. a user has to explicitly bind the this
of function to the parent elements. They also provide a short and implicit way to return values from a function.
const sum = (a + b)=> a+b
const sqaure = (a)=> a**2
// can even be shortened to square = a =>a**2, when we have a singular argument.
// this is the same as
function sum(a,b){
return a + b;
}
//sum()
function square(a){
return a**2
}
// React Example
function List({List=[]}) {
return (
<ul>
{list.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
) }
Conclusion
Learning reactjs shouldn't be a struggle, after being comfortable with the basics of javascript. You just need to know the most commonly used concepts that are being used in a react application. Learning theses topics will definitely make you more comfortable to take a launch into learning reactjs.
Other notable things, you can learn are ES6 classes and async/await.
Thanks for reading, see you in the next article!
Follow me for more interesting articles 👇👇
Posted on August 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 5, 2024