Haven’t posted in a long while… That’s because I’ve been storing all my bytes of knowledge on another platform — this cool tool I chanced upon recently: https://gingkoapp.com/. I would’ve liked to use Quiver but I don’t do Mac (yet), so the Gingko app will do for now.

Also excited to be starting my SWE career at Carousell!

JS Scribbles


Closures are functions that have access to their parent scope. To quote MDN, “these functions ‘remember’ the environment in which they were created”. If you’ve worked with JavaScript extensively, you would know that functions naturally have access to the variables in their parent scopes, so this is actually quite intuitive.

This is especially useful when we’re working with asynchronous/callback functions. We can declare them ahead of time before they actually run, and we can rest assured that when they do, they have access to variables declared externally.


Using the Var keyword defines a variable either globally or locally to a function. Using the Let/Const keyword defines a variable within a block scoped (i.e. within an if statement, for loop, etc). Pretty sure I covered this in my ES6 post.

Function Declarations vs Function Expressions

Declaring someFunc(){…} and var someFunc = function(){…} has a different impact on your code. The former is known as a function declaration while the latter is known as a function expression (i.e. we call it an expression as the function is part of a “larger” statement). Try not to confuse this with C terminology, where a function declaration is actually its prototype, and the actual implementation is known as a function definition.

In the first case, the function someFunc is immediately hoisted to the top of the function, so technically it does not matter where you declare it within the function, as long as you happen to use it in the function scope. If two declarations exist for the same function name, priority will be given to be one declared later.

In the second case, the variable someFunc is hoisted to the top as well… but not the anonymous function assigned to it. This assignment only occurs at where you’ve written var someFunc = function(){…}.

Once you’re sure you’ve internalised this, try out the following short quiz.

Algorithms Workout 3: Linked Lists

Dealing with linked lists can be a bit tricky sometimes, they’re kind of like arrays, but not quite. Although their one-dimensional structure makes them relatively easy to manage, I’ve learned to be more careful with how I work with their indexes.

If we’re working with a singly linked list and want to reach the i-th element in the list from the head, we should only iterate current = current.next i-1 times. Obviously, this is because we are already at the head, so we would only take i-1 steps to get to the middle node.

It can be easy to to forget this. In the following code, I obtain the middle index of a linked list by subtracting 1 from the halved (and ceil-ed) value of the list length. I think the act of having “accounted for a 1” somehow makes one less inclined to subtract another 1 (yes you can read that again), but in any case, I have to start the subsequent traversal loop from 1 rather than 0.

Screenshot from 2017-03-16 12-35-15.png

Gayle (CTCI authors) reminds readers to keep two techniques in mind when working with linked lists:

First, is the “runner” technique that involves using a running pointer which we can use to measure the length of a linked list, traverse a few steps ahead of the current pointer, etc.

Second, is recursion.

I come from an OCaml background, so perhaps it is for that reason that I have the bad habit of insisting that my recursive calls should somehow exist within my return statement (which often looks pretty elegant when we’re doing top-down DP).

In some cases, that becomes too cumbersome. Quite often, you want to build up your recursive return values (i.e. Bottom-up/Memoised DP) from the base case, and then reference them as necessary at higher-level calls.

Qn: Given two linked lists where each node represents a place in base-10, produce their sum. (e.g. A: 5 -> 6 -> 7, B: 6 -> 7 -> 3 -> 4, A+B: 7 -> 3 -> 0 -> 1). Assume that the first node starts at the highest place.

Full solution at: https://repl.it/GZug/O2

Our expected return value is a new linked list (sumList) representing the sum of linked lists A and B. Our general strategy here requires to start recursing from the last pair of nodes in A and B.  This question is particularly tricky because you:

  1. Have to manage uneven linked list lengths
  2. Can’t carry values “forward”. If the sum of two nodes is such that 6+6 = 12, the 1 has to be carried “backward” to the sumList node that holds the sum of the previous pair of nodes in A and B.

Screenshot from 2017-03-17 12-29-21.png

Dealing with 1) is quite easy, we can just pad the shorter list with zeroes. Dealing with 2) requires us to declare a wrapper class for each of our nodes in sumList. This wrapper class nodeWithCarry would possess a node field and a carry field. Using bottom-up recursion we can obtain the nodeWithCarry for the next set of nodes down the chain, and then reference the fields on this object to create a new nodeWithCarry for the current pair of nodes we are examining.


Algorithms Workout 2: Matrix Rotation

Given a 2D matrix (i.e. 2D array), how do you rotate it by 90 degrees, in place?

Rotating the matrix in layers (rotate the outermost layer and then rotate the second outermost layer) is one way to approach this problem. What is perhaps the most apparent problem of this approach is that of overlapping information — if the top row is replaced by the row on the left, how can we transfer the original contents of the top row onto the row on the right?

A straightforward solution to this would be to use an another 2D matrix to hold the transformed cells. This way, we can always use the original matrix as reference and don’t have to worry about losing information.

There is however, a more space efficient way to do this. As we iterate through the cells of each top/left/bottom/right row, we use a primitive temp variable to store the data for the one particular cell so that we can apply it again later. This is clarified in the code below:


Though this algorithm does not technically rotate the matrix in place (it does require the temp variable), it is extremely space efficient.

Other takeaways

  • When dealing with a string that has been rotated (i.e. waterbottle -> terbottlewa), concatenating the rotated string with itself (terbottlewa = terbottlewa + terbottle) will produce a string (terbottlewaterbottlewa) that contains the original string as a substring.
  • When working with 2D arrays, the first row and first column can potentially be used as flags.

Algorithms Workout 1

With capstone project deadlines, job applications and a full academic load on my plate,  I should probably try to find ways to make life easier for myself at this point…

Tempting, but nope. For the next two weeks, I’ll be committing to a daily routine that involves working on algorithms-based questions. I’ll be spending about a couple of hours a day working on problems from the CTCI book. I feel that my familiarity with data structures has slipped, so I’ve decided to do this in order to refresh my knowledge before I step into my first interview with a Big 4 company.

Day 1 Takeaways

  • Permutations of a String

We want to return a list of permutations for a given string. For the zero-th index of every permutation, we have choices that comprise the set of unique characters present in the argument string (e.g. for “carry”, we can have ‘c’, ‘a’, ‘r’, ‘y’ at the 0th index).

As we iterate over each of these unique characters, we permute the rest of the string (i.e. the substring) and append each sub-permutation to the selected character.


  • Instantiating array of zeroes in ES6
var a = Array(5).fill(0);
  • Binary searches are effective when working with sorted arrays/lists
  • Hash tables are useful for keeping track of unique elements in a list/matching elements between lists
  • Use bitwise operators as a set of flags for space efficiency
var checker = 0;
// -- setting flag
checker |= (1 << pos)
// ^same as checker = checker | (1 << pos)

// -- checking flag
if (checker & (1 << pos)) {...}

Operating Systems I

A large part of my final semester has been about solidifying my domain knowledge in areas related to systems and networks. I hope that, in the limited space of time I have left in college, I will be able to learn as much as I can about these topics before I move on to the working world. This post (as well similar ones in the future) will review some of the core material taught by my professors and explain ideas at a very conceptual level.

What happens when we first start our computer?

When we first initialise our CPU (fancy way of saying start our computer), the first thing that runs is your BIOS (Basic Input/Output System).  Your BIOS is known as your CPU’s firmware; it a piece of software that communicates directly with your machine’s hardware. The BIOS can be configured by you, the user, on start-up (try pressing F2 right after your computer begins to boot) and it runs your machine according to whatever has been configured. It starts up the various components of your machine such as your CPU (Central Processing Unit), RAM (Random-access Memory), GPU (Graphics Processing Unit), etc. Finally, the BIOS confirms that these parts are working as they should, before handing control over to your OS. This video, created by techquickie, covers this process very succinctly.

What is the OS? What does it do?

The OS is wonderful piece of software that manages the hardware and software resources on our computer and makes them available to the various processes we want to run.

Every time we run a program or an application on our computer, a process is created. What the process does is defined by code. In basic terms, every line of code we write is just an instruction (or a set of instructions) for the computer. So, for example, if you somehow manage to run two instances of the same video game on your computer, you would be running two processes.

What kinds of resources does the OS manage?

Most computers today are manufactured with multiple cores. A core is also known as a processing unit; it reads and executes the instructions (code) associated with each process.

It is important to note that each core executes instructions sequentially (i.e. one at a time). Thus, we can execute multiple instructions simultaneously only if we have multiple cores!

We can think of the processing power provided by these cores as resources that our machine possesses. Given x number of processes and y number of cores, how do we allocate processing power? Which processes should be prioritised? When we run multiple programs on our desktop (e.g. Spotify + Dropbox + Chrome) such that x is greater than y, how can we give the user the impression that everything is running concurrently?

Allocating resources

The scheduler is a component within the OS that decides how to divide a particular core’s processing power. Suppose that we have a single-core machine, and three different programs a, b, and c are currently running on this device. The scheduler creates a rotating schedule that delimits specific intervals of time for the core to run processes a, b, c. The rotation occurs so rapidly that, from the typical user’s point of view, it seems as though all three processes are occurring at the same time!

This should provide the layperson with a bare-bones introduction to operating systems. There’s an entire universe of other concepts worth covering: inter-process communication (pipes), threads, signals, locks, semaphores… but that’s for another time.

Unpacking Webpack 2, HMR & Loaders

Just worked through this excellent Webpack 2 tutorial by Emil Oberg. I like how straightforward and accessible it is; Oberg does not assume that you know anything about bundlers, ES6, NODE_ENV variables, etc. Let’s go through some of the concepts and code from his tutorial.

Webpack is a JS file bundler that allows us to combine all of the files we have in our /src (source) directory into our /dist (distribution) directory. In essence, Webpack takes our src/index.js, “pulls” in all of its dependencies (“import”s and “require”s), and organises everything into a single dist/bundle.js file. It can do the same for other The main difference between Webpack 1 and 2 is that the latter accepts ES6 imports, while the former does not.

Here’s an overview of our directory, for a clearer picture:


And here’s a look at the scripts our package.json file that we intend to run via npm:


The scripts build and dev both invoke webpack. build runs webpack once for production, while dev runs dev-server.js, a webpack development server file that 1) watches our source code for changes and 2) runs webpack every time a changed is noticed.

Here, we’ve not specified any settings for Webpack in our npm script. This is because we configure the settings we desire in a separate webpack.config.js file. We’ll get into how this file should look like very soon, but before that, let’s go through how we can actually watch the files we work with so that they are re-compiled whenever a change is made. We have two options:

  1. Hot Reloading: Rebuilds bundle.js + (Refreshes the browser or Refreshes bundle.js)
  2. Hot Module Replacement: Rebuild chunk + Replace chunk in browser

The latter is preferable because it doesn’t refresh all of our JS code. In doing so, it preserves the application state. How do we set this up? We create a webpack development server using webpack-dev-server. This server is essentially “a little Node.js Express server [that] uses the webpack-dev-middleware to serve a webpack bundle” (as defined by the official documentation).

Hot Module Replacement (HMR) with webpack-dev-server


In the above code, we 1) require webpack, 2) require the webpack configuration file, 3) define some basic settings and 4) tell the server to listen on a particular port — in this case, 8080.

WebpackDevServer expects a “compiler” that takes in the webpack config file as an argument. This is webpack-dev-server’s way of referencing our webpack config file for instructions on how it should bundle our code.

We enable Hot Module Replacement (HMR) by:

  1. Adding an entry point in webpack.config.js (which we haven’t seen)
  2. Adding the HotModuleReplacementPlugin in webpack.config.js
  3. Adding hot:true in our webpack development server configuration (as done above).

Now, let’s see how we can write our webpack.config.js file:


In development mode, we use three JS files as entry points:

  1. ./src/index.js is the root JS file for our app’s source code.
  2. webpack-dev-server/client?…  informs webpack of the client entry point (localhost:8080) and activates webpack-dev-server’s inline mode. For more on inline (versus iframe) mode, refer to the docs here. It’s not clear to me why we can’t have an {inline: true} option inside webpack-dev-server.js.
  3. webpack/hot/dev-server injects specific JS code which allows HMR.

It should be pretty clear why we don’t we use all three files as entry points in production!

In development mode, the HotModuleReplacement plugin allows us to do all of that HMR magic. In production mode, we drop the HMR plugin and use the UglifyJs one, because we shouldn’t bother ourselves with hot module replacement in a production environment. The UglifyJsPlugin minifies our code (e.g. reduces lengthy variable names to single letters).

An important note: We also have to enable HMR on our app’s JS source code. To do this, we add the following lines to our index.js:


Once done, we place the entry and plugins arrays under a single object. To belabour the point, we’re exporting this webpack config object because we rely on it whenever we run a script that invokes webpack or dev-server.js! Here’s what our module.exports object might look like:


You’ve probably noticed two new items at this point — ‘source-maps’, and module loaders (which we can think of loaders as file “converters” or “transformers”). Let’s go through all of them.



If we’d like to transpile our ES6 (ES2015) code into ES5 code, then we’d have to use Babel. The dev-dependencies to install are babel-core, babel-preset-es2015, babel-preset-stage-0 and babel-loader (of course).

babel-core is, as its name implies, the “core” of Babel. It’s the transpiler. Meanwhile, the babel-preset libraries are provide configurations for transpilation. We define a .babelrc file in order to use these presets.babelrc.png

babel-loader has a few fields. The test field defines which files are to be run through babel. In this case, we only care about JS files and we use Regex to sieve those out. We exclude node_modules in order to save on overhead costs, especially since most of the JS files in the node_modules folder are already written in ES5.

file-loader (& url-loader):

In our source code, we can write out an image.js file as:


(Refer to the snapshot of the directory, if you’re lost as to where this should go)

Webpack typically handles JS, but how should it manage our media resources such as this one? Using file-loader, we can load all png|jpg|gif files into our /dist folder and hash their filenames (specifically, it’s an MD5 hash). You can see this in action in the directory snapshot shown earlier.

url-loader is another loader worth mentioning at this point. We don’t always want the browser make a new HTTP request for every media resource — especially if the file is small. This is where url-loader comes in; it allows us to define a size limit under which a media resource will be converted into a DATA URI.

style-loader and css-loader:

We require our style/style.css in our index.js file. style-loader interprets the css while css-loader injects it within the header tag of our webpage.

source-map (*not a loader, but a Webpack devtool):

The source-map devtool provides mappings between our source code (/src) and our bundled code (/dist). Why is this necessary? When we run our code and encounter errors that immediately alert us of their presence in the browser console (in our Chrome Developer tools), clicking on the direct link on the right does not bring us to the problematic code in our bundle.js, but instead, our actual source code.

Wrapping Up

Webpack 2 offers plenty of other useful tools that I won’t go into detail here (such as “tree-shaking” features that can help developers eliminate dead code). Regardless, I hope I’ve provided some insight into how we can use some of the great tools provided by Webpack (and webpack-dev-server).

Homie: Progress Update

Before I finish up my post on Webpack, I’d like to write about some of the progress I’ve made on Homie, a capstone project that I’m working on which targets foreign domestic workers in Singapore.

Revamped Homie’s Tasks


I revamped the “Tasks” section and gave it some additional functionality so that it’s more than just a simple to-do list. As of now, each Task can have:

  1.  An alert associated with it that triggers at a specific time
  2. A timer/progress bar associated with it that starts once the user tries to check it off

Didn’t code this out using any fancy library, just relied on plain old JavaScript and web storage (localStorage).

Conversation with HOME officials

I had the wonderful opportunity of meeting Jackie and Sanjana, both of whom work at HOME (Humanitarian Organisation for Migration Economics). The organisation does good work; they support the needs of domestic workers as well as male migrant workers through various programmes by providing shelter, counselling and life-skills training. I gained some much needed perspective on the needs of migrants workers in Singapore and I’ve come to realise that some features of my app make sense while others don’t.

In particular, I thought about including a social feature for Homie, but Jackie informed me that workers from Indonesia and the Philippines typically come to Singapore knowing fellow countrymen and countrywomen who arrived in the city earlier. She recommended that I provide up-to-date information on events organised by HOME as well as other migrant worker organisations.

In the coming weeks, I hope to be able to 1) speak with caregiving specialists and 2) get in touch with similar organisations such as TWC2 (Transient Workers Care Too) and CDE (Centre for Domestic Employees).

Deployment + Reverse Proxy Server

Successfully deployed with Digital Ocean for the first time. I learned how to set up and configure NGINX, a reverse proxy server that directs incoming requests to the appropriate back-end. Assuming that a request is directed to the default port on our server (port 80), we can ensure that requests are handled by their corresponding back-ends (listening on port 8080/3000/etc) by modifying the nginx config file found at /etc/nginx/sites-available/default. There are plenty of tutorial written on how to do so, such as this one.

NYE 2016, Next Steps and Redux

15732525_10154259044930922_1823684632800428788_o.jpgNew Year’s Eve 2016: Counting down with friends at Marina Bay Sands

I’m glad that 2016 is over and I’m grateful that I was able to celebrate the occasion casually with my Yale-NUS classmates. We’re all about to move on to the next phase of our lives and I’m excited to see where everyone’s headed.

I started coding in August ’15. Since then, I’ve learned plenty about various programming paradigms, languages, frameworks and libraries. Yet, there’s still so much more to learn and explore.

While I’ll be taking OS, Interaction Design and (very) possibly ML classes in the coming semester, there are topics that I also hope to pursue independently. ES6 + React + Redux + Webpack are just my first steps on this self-guided learning journey. I would very much like to dive into the domains of information security and computer networks as soon as possible, but the fact remains that I have to focus on my senior year capstone project, Homie.

With regards to Homie, I plan to reach out to as many migrant worker organisations as possible over the next couple of weeks. I spent the last two weeks focusing on React, Redux and job applications, but at this point, I would prefer to just focus on my capstone project.


In my previous post, I reviewed React’s components and talked how we can pass bits of application data down the component tree using this.props. To reiterate some of the points I made: Components are essentially “hyper-functional” custom HTML tags. Each of them can be associated with a particular state; an data-storing object that we can access with this.states. Collectively, the states of an app hold all of the front-end data.

Keeping track of all of an application’s states can be messy ordeal. This is where Redux comes in handy. Thanks to Wes Bos’s amazing online tutorial, I was able to understand some of the core concepts in Redux.

Redux provides us with Providers, Reducers, ActionCreators and a Store.

A store is minimally a combination of 1) one giant object that contains all of our front-end data and 2) a root reducer. However, when people speak of Redux stores, they’re usually just referring to 1).

What are reducers then? Reducers are functions that handle actions. An action can be something as simple as the click of a Like button or the submission of a HTML form. A root reducer is simply a combination of all the reducers that we’ve written.

When an action is dispatched (i.e. it occurs),  the reducer receives it and figures out how to process this new information. You can think of the relationship between action and reducer as being somewhat analogous to that of events and listeners.

Finally, the provider is a component from the react-redux library that exposes the store to our app. We can make the Provider component the root component of our app and then nest the Router component (from the react-router library) inside it.


Although the Redux store lies at the heart of Redux, let’s first examine what actions look like. Action are simply objects that contain a type field as well as all other relevant information. To use an example from Bos’ tutorial:


The above code is taken from our actions/actionCreator.js file. The above functions are actionCreators whose purpose is to return action objects. We make sure that the action object contains all the relevant information we need. In the case of addComment(…), we make sure to include the postId, the author, and the comment itself as parameters.


The following code describes two reducer functions:reducer.png

When the ‘ADD_COMMENT’ action is dispatched, all reducers respond to it. However, we are able to make a targeted response (i.e the postComments reducer reacts to the ‘ADD_COMMENT’ action instead of some other reducer) by adding conditionals to our reducers that will check the action type.

Once we’re done writing all out all of our reducers, we export them, import them into a separate file and combine them to create a root reducer.



With rootReducer in place, we can start creating our store. Once we create a defaultState object that contains all of the relevant data from our database, we can instantiate the store by passing rootReducer and defaultState as arguments (enhancers is an optional parameter).

Hooking our Store and Actions up to our Main Component


With our store and actions in place, we can connect them to our Main component.

In the above code, we literally map our state (i.e our store) and all relevant actions to our Main component (which contains all of our render(){…] code). This means that we will be able to will be able to access store information and dispatch actions through our Main component’s this.props field. We export our Main component together with its new properties as an App component.

Viola! We now have an App component that has been linked up with our Redux reducers, actions and store. We can easily integrate this component with react-router on our main JS file.

Screenshot from 2017-01-02 15-38-31.png

That’s it. We’ve integrated Redux with React.

Up Next: Webpack.



I picked up AngularJS this summer. The framework has been my default go-to tool for the last six months. As 2016 comes to a close, I’m happy to be finally moving on to a new framework: React. Wes Bos, the creator of these React + Redux tutorials, offered me a student discount for his online course after I emailed him earlier this week. I’ve worked through the bulk of his videos since and I can’t wait to start developing my web portfolio with the skills I’ve acquired.

First impressions:

  • React seems to handle dynamic content better than Angular.
  • Melding JS and HTML together in the same file is interesting. With React, it seems more common for developers to insert JS-logic inside HTML, than with Angular.
  • React’s use of components encourages developers to conceptualise their UI as being composed of small chunks that fit together in a tree structure.
  • I’m glad I worked through Ryan Christiani’s ES6 tutorials (previous post) before starting out! Having a strong grasp of ES6 ensures that you don’t get lost in the process of learning React 15.

I won’t outline the differences between Angular and React in this post. There are many articles out there that already do so and I simply don’t have the time for that! Instead, I’ll use this post as an outlet for me to recall what I’ve learned over the past few days.

React, Essentially

Components are the fundamental building blocks of React. In a nutshell, they are simply HTML tags with a whole lot of functionality packed inside of them. Say you want to build a music app. You’re probably going to want to have an App component. Inside that App component, you might nest a Player component, a Playlist component, and so on…

Essentially, React apps are built with component trees. A component tree is structured such that child components are nested inside their parent. If you are familiar with the Document Object Model (DOM) and JQuery, this should be easy to understand.

In the case that you opt to use the ‘react-router’ library to build your application, BrowserRouter will probably lie at the root of your component tree. This particular component examines the browser’s URL before determining which of its child components to render. We see this in action with the following Match/Miss tags.

Screenshot from 2016-12-26 12-36-16.png

The component we often care about the most is the App component. This component usually holds the application’s data (or as we usually say, the application’s state), in a JSON object. Using what we know about ES6, we can define an App component as follows:

Screenshot from 2016-12-26 12-49-56.png

A quick note: Usually when people speak of components, they refer to an instance of a component. Every component is instantiated once whenever its name is tagged in HTML.

As seen in the above code, we define a constructor for component which allows us to:

  • Call super(), in order to inherit properties from React.Component
  • Bind methods not found in React.Component to the component itself
  • Define a state

Here, our class definition is still not complete. We need to add the associated methods (e.g. addFish, updateFish) and more importantly, return the actual HTML we would like to render. The following snapshot continues the class definition for the App component (and it skips several lines of code).

Screenshot from 2016-12-26 12-57-24.png

The render() function we’ve inherited from React.Component allows us to return HTML. Yup, you read that right: HTML, not JS. The browser simply renders whatever we’ve returned inside render(). In a way, this segment of our class definition replaces the template.html files we write for our Angular apps.

Not all components require class definitions or render() functions. Stateless functional components exist, but we won’t cover them in this post.

State & Props: Data, Down The Tree

How do we pass data from one component to another (i.e. “down” the component tree)?

Let’s suppose we want to create a very simple app for a dog which holds and displays its information. Let there be two components — an App component and a Dog component. The App component holds the dog’s information in its state, while the Dog component displays that information.

Let’s examine the following two chunks of code:

appC.pngThe App Component

dogComp.pngThe Dog Component

As seen above, we pass information from a parent to a child by inserting that information as an attribute on the child’s HTML tag. In this example, we pass name, weight and an updateDog function as attributes of Dog.

On the child’s end, we display that information within curly braces {} and call this.props. this.props is a reference to all the data we’ve passed from the parent to the child.

State & Props: Data, Up The Tree

Passing parameters as attributes on your child component’s HTML tag seems easy enough. What if you wanted to pass data “upstream”? What if you wanted to make changes to the parent’s state through the child?

Let’s look at the same two sets of code again. Inside Dog, we’ve created a HTML form which can update the application state. The first thing we do is to make a reference to the items in the form (i.e. weight, name). We use ref functions (not ref strings — which have been/will be deprecated) to achieve this.

As seen in the HTML rendered by the Dog component, a form submission calls createDog(e). The anonymous function wrapped around createDog is an event handler. This handler takes in a parameter e, which refers to the event itself. It is important to note that createDog calls updateDog and that the latter is not bound to the Dog component, but rather, the App component. This is why the Dog component has access to the App component’s state; its createDog(e) function invokes updateDog() which allows it to update the application’s state accordingly.

Wrapping it Up

While understanding components (and how data is passed between them) is an essential part of React, it is still just one aspect of the framework. For more details on some of the nuances that React learners often overlook, I highly recommend Bos’ tutorial as well as this one by Learn Code Academy.

Up next: Redux.