A few weeks ago, I made a presentation and a youtube video introducing Angular (and JS developers in general) to ReactJS. It seems like React became a framework many want to try but somehow, it’s always out of reach. A part of the reason for that is that there’s not a “why” attached to the design choices, nor are there comprehensive tutorials introducing React simply and concisely.

Part of the reason is that once you get into React, you have this tendency to use more and more tools like ES6, Browserify, Babelify, Flux, and lots of others. For this tutorial, I’ll handle that stuff all the way at the end after you get the hang of ReactJS and its basics. No need to overcomplicate things.

If you’d like to view the slides, I have it up on Github pages. The code examples are on Github as well. I have the full example app running on my project site.

About React

Let’s talk about React. React is the “View” layer of a single page application. What that means is that React ships feature-light, there are no “controllers”, no “models”, and no utilities. With Angular, you get, for instance, $http and $animate . React doesn’t have any of that.

The awesome thing about that is that React becomes just the “view”, everything else is up to you. In many ways, React feels more like a library rather than a framework and you’ll feel much more immersed in Javascript rather than conventions of the framework.

The big advantage of React is its inherent structure. React encourages one-way data flow (no two-way binding). Which means that data flows into an element but not back out of it to its parent. And say goodbye to scopes! This will become more understandable with examples. Right now, it feels counterintuitive but just wait.

ReactJS was created by Facebook and is used for Facebook as well as Instagram. It’s also used by Netflix, Yahoo, Sony, and many others. It was released in 2013.

Note that React is canonically associated and used with Flux methodology (briefly covered in this article).

Angular way of doing things

Because this tutorial is partially meant for Angular developers, let’s look at a trivial example of showing a list.

<div ng-controller="itemController"> <div ng-repeat="item in items"> {{ item.name }} | {{ item.id }} <a ng-click="delete(item)">×</a> </div> </div>

and the JS:

angular .module('item', []) .controller(itemController) ; itemController.$inject = ['$scope']; function itemController($scope) { $scope.items = []; $scope.delete = function(item) { //deletion logic }; }

Everything seems pretty good right now. We have an item list, we have deletion logic. Let’s add some interactive code.

angular .module('item', []) .controller(itemController) ; itemController.$inject = ['$scope', '$http']; function itemController($scope) { $scope.items = []; $scope.delete = function(item) { //deletion logic }; $scope.refreshItems = function() { $http({ method: 'GET', url: '/api/items' }) .then(function(response) { $scope.items = response.data; }); }; $scope.refreshItems(); //get initial itemset }

So what’s the problem here?

Right now, not much and that’s okay. Angular is a good framework.

The only issue that comes up here is the fact that whenever we get a new itemset, Angular refreshes the entire list DOM rather than just the items that changed. That’s a performance hit. There are tons of performance techniques to minimize these kinds of refreshes. To put aside this strawman argument, let’s talk about some bigger, less apparent issues that come up when you’ve already worked with Angular for a while:

Two-way binding does not always propagate When using a directive and using its scope ability that two-way binds variables, there are instances when a variable just won’t update. Where the directive and controller will have the same variable but it won’t synchronize. I’ve encountered this often; however, I wish I had an example on hand.

This issue can be solved with a simple $watch .

The other thing about directive is that they’re count-intuitive. When you pass in a scope variable, you’ll do some adjustments, like so:

function link(scope) { scope.breadcrumbs = scope.items.map(function(item) { return item.path.split('/'); }); }

The problem is that if scope.items refreshes, scope.breadcrumbs will be out of sync so you have to setup a $watch .

$digest does not trigger wiht external data change Setting up a timeout , or simply using your own custom pub/sub system that controllers/directives hook into can cause data in $scope to be out of sync with the view, meaning that when that data updates, the view won’t run a $digest . If you want to do an AJAX request or a timeout (for disappearing notifiction for instance), you’ll have to use built-in methods like $http and $timeout which will run a digest. For that pub/sub system, you have to use $rootScope functionality. Anything custom outside of Angular will not propagate. I learned that lesson the hard way when building the Angular side of Foundation for Apps.

But you can always run $scope.$apply to force a digest cycle. The problem? Forced $digest cycles can cause errors.

Pub/sub flow is discouraged One of the last problems with Angular is that pub/sub flow is discouraged. There are all kinds of built-in pub/sub funtionality built into Angular but every article I’ve read on it discourages using it which is bizarre. The problem is really that certain functions will cause all scopes to be notified of changes which is a huge performance hit.

In the end: In the end, Angular is still an awesome framework and I recommend using it. The places where ReactJS really shines is architecture and composability. That and the fact that it really feels like JS rather than working within another system.

Enter ReactJS

Here’s an example React component:

var MyComponent = React.createClass({ render: function() { //all data transformation happens here return ( //JSX goes here ); } });

React in a way, resembles Angular directives but that’s all there is: these directives. In React, they’re called “Components”. When creating a component, certian methods are run (if available). The main one is render which uses data that React exposes (like state, props, etc. more on that later) and uses it to build a fake DOM using “JSX”.

The beauty of ReactJS is its one-way flow which is easier to follow and understand. There is no $digest nor any way to setup $watch . But let’s look at all the cool things about React first:

Isomorphic. Isomorphic in this context means that ReactJS can run on the back-end and front-end. You can easily reuse and share code between the two.

No $digest cycle. IN ReactJS there are no scopes or $digests. There are “states”, when a state updates, React runs a “render” method on each component (similar to a link method for directives). In a way, this is similar to using $watch and setting it to the entire scope (which you can’t do). But without a digest cycle, the render method gets called when anything changes the state, even external logic! I’ll show you how this works in a little bit.

Virtual DOM renders only what’s necessary. Virtual DOM is a programmatic representation of the current DOM. When the render method gets run, it uses new data and reruns all of its logic, it then returns what the new DOM should look like. That gets diffed against what the DOM currently looks like. React then tries to batch its DOM operations to do only what’s necessary in the most efficient way possible.

Rest of the stack is variable. If you remember the days of yore when Backbone was the big deal, this should sound familiar. React deals with only one aspect of the app, the rest is up to you. In fact, many examples out there today use React and (gasp!) jQuery together. However, React is generally used with Flux. The kicker is, there are tons of Flux libraries out there, solving different problems and present new solutions. And they grow off one another. This is good news.

There are no “templates”. What I showed you earlier is technically not a “template”. However, it is “template-like”. The big difference is that you’re not using HTML directly, you’re using JSX. And JSX is never used directly, it’s compiled to plain old javascript.

First class ES6 support ES6 is slowly becoming the big deal these days and ReactJS is fully compatible and ready for it. With Angular, DI and module packaging is cumbersome at best. But honestly, it just doesn’t work. With React, you’re tempted to use ES6 for everything.

Note Things aren’t always so straightforward. Both frameworks have their merit and with AngularJS getting a huge facelift for its 2.0 release, things will fundamentally change.

Your first component

Follow along with the code for this exercise.

Let’s dive right in. First, let me remind you of JSX. JSX is an HTML-like language that React uses; however, it has to compile it first. Meaning that it’s not used directly. For this tutorial series, I’ll skip the precompile process, and use an in-browser JSX compiler. This means that our app will take a little longer than usual to render the initial HTML load.

If you’re using Bower, just run bower install react --save . The react bower repo contains two files we’re interested in: react.js and JSXTransformer.js (the JSX front-end compiler). Include those in your project.

You can always include those files from a CDN.

Since we’re using the JSXTransformer, make sure your React code uses these script tags:

<script type="text/jsx"> //javascript and JSX goes here </script>

Our first App

Let’s look at how React gets initialized. We’ll create a mount point , an element which React will look up and use as the root element. Similar to what we do in Angular using ng-app= , except we won’t modify our HTML with any React jargon. Note that it’s advised against using body for a mount point.

<div id="example"></div>

It’s basically a non-descript element. And now, let’s mount it and render some HTML into it:

React.render( <p>This is rendered text.</p>, document.getElementById('example'))

Now, obviously, this doesn’t do much of anything other than put that paragraph into the example div. But the syntax is obvious: React.render(myApp, DOMElement) . You can use any method to get that DOM element from getElementById to querySelector.

Our first component

Let’s move onto a component. Building a component is pretty simple. Let’s create a second example HTML element:

<div id="example-2"></div>

and now, let’s create a true React component:

var GeneratedText = React.createClass({ render: function() { return ( <p className="secondary"> Component-rendered text </p> ); } }); React.render( <GeneratedText />, document.getElementById('example-2') )

There are a few things that should jump out at you immediately:

the component is stored as a regular variable. the variable name is used in JSX as <GeneratedText /> self-closing elements. JSX looks just like HTML except for a few minor differences. For instance, we use className instead of class.

// insert an example of JSX compiled looks like

Our composed component

Lastly, let’s look at what happens when you include a component within another component and how to go about doing that.

<div id="example-3"></div>

and the JS:

var ContentText = React.createClass({ render: function() { return ( <span> Composed components rendered </span> ); } }); var SecondaryContent = React.createClass({ render: function() { return ( <p className="secondary"> <ContentText /> </p> ); } }) React.render( <SecondaryContent />, document.getElementById('example-3') );

The same way we use React to mount our app (by referencing a JS variable as a custom JSX element), we “mount” (or rather include) our child composed element. Note that the JSX that the render method returns has to have exactly one root element writing something like:

<p className="secondary"> <ContentText /> </p> <p> Second paragraph </p>

would be illegal and you’d have to wrap it in a div or whatever other element that fits.

This is what the result should look like:

And the code for the entire page is available here. Obviously, I’m using some kind of a UI library to spruce things up.

Props

Follow along with the code for this exercise.

You might be wondering how you can pass data to a child element from the parent. I did say this is a one-way street so let’s figure out how to use it.

For every React component, React provides a few different pieces of data and methods available. I already mentioned how render is something React looks for when it wants to render a component. There are other methods that React automatically invokes. Outside of that, React also populates several objects within your React component. These are accessible via this .

this.props is where properties passed to the component are stored. A special one this.props.children stores the content between the closing tags of your element. This might sound confusing so let’s look at an example:

<div id="content-1"></div>

and the JS:

var SecondaryButton = React.createClass({ render: function() { return ( <span className="button secondary"> {this.props.children} </span> ) } }); var ContentBlock = React.createClass({ render: function() { return ( <SecondaryButton> My button </SecondaryButton> ); } }); React.render( <ContentBlock />, document.getElementById('content-1') )

Whoops, forgot to mention something. JSX includes a way to evaluate Javascript inside of it with single braces {} . You can literally write any JS in there. Putting a variable between the braces shows that variable.

As you can see the ContentBlock component uses the SecondaryButton component. Instead of just using a self-closing element like so: <SecondarButton /> , we’re going to pass some data down into the component. And guess what? You can pass down more JSX. This is akin to directive transclusion in Angular if you’re familiar with it.

That data will be available in this.props.children .

Passing more data

Obviously, passing JSX from parent to a child is great; however, what if we want to pass more than that?

HTML:

<div id="content-2"></div>

and the JS:

var BetterButton = React.createClass({ render: function() { var classString = 'button '; classString += this.props.buttonType; return ( <span className={classString}> {this.props.children} </span> ); } }); React.render( <BetterButton buttonType="secondary"> My Better Button </BetterButton>, document.getElementById('content-2') );

Again, some things to look at. We can use the {} safely just about anywhere. By doing className={classString} , we’re evaluating the classString as a className.

Second, we can pass props other than children as attributes of a component like so:

<Component myProp="some value"> <p>prop children</p> <p>go here</p> </Component>

The attributes are immediately available as this.props.myProp . This way, we just create a button with an additional type we can pass through buttonType prop.

And here’s what it all looks like in action:

Passing data and building reusable components

Follow along with the code for this exercise.

You should have enough info right now to build component that are a little cooler than writing straight HTML. Let’s spice things up a bit by feeding our components some data and using that data to build a sweet-looking list.

<div id="content"></div>

For our data, we’ll create an array of objects that contain person data:

var data = [ { name: "Antonin", description: "Web developer" }, { name: "Juno", description: "Web designer" }, { name: "Alix", description: "Web designer" } ];

Next, let’s create a “meta” actions, I want to be able to display a person’s info and allow users to “like them”:

var MetaList = React.createClass({ render: function() { return ( <ul className="list-meta"> <li><a href="#">Like person</a></li> </ul> ); } });

Nothing special so far. Now let’s create a Person component:

var Person = React.createClass({ render: function() { return ( <li> {this.props.person.name} | {this.props.person.description} <MetaList /> </li> ) } });

As it’s becoming obvious, we’ll pass the entire person object from our data array as a prop to this component. We’re also including our MetaList.

Finally, to put it all together, we’ll create a PeopleList to hold all of our Person s.

var PeopleList = React.createClass({ render: function() { //no ng-repeat or foreach var personNodes = this.props.data.map(function(person) { return ( <Person person={person} key={person.name} /> ); }); return ( <ul className="block-list comment-block"> {personNodes} </ul> ); } }); React.render( <PeopleList data={data} />, document.getElementById('content') );

The order with which I explained all of this is a little backward so let me run through the code real quick in sequence of execution:

we mount our app and pass in our data array as a data prop. we access the data prop with this.props.data . Using Javascript’s map function, we iterate over all our items in the array and return JSX which contains a <Person /> component We pass our each item into our person component as a person prop. We use the person’s name as a key . The key is like an “id”, letting React know how to associate data with the correct element. We pass our new array of Person components into our PeopleList JSX via {personNodes} . The Person component renders the person’s name and description using {} and this.props.person where the person data is stored. Lastly, we include our MetaList which is currently just plain JSX with no data attached.

>Review so far

Let’s take a break and review what we’ve learned so far:

We don’t use scope or anything similar. This means that Components that want to share information have to explicitly pass it around through props . React components and Angular directives are very similar: they both use element attributes to pass data, they are self-contained, and they are declared via custom element names. React uses a class-based system. React is pretty much all view. Lots of Javascript, little use of built-in conventions.

Let’s talk Data

Follow along with the code for this exercise.

I said that React pairs well with many other libraries. In our next example, we’ll use jQuery for AJAX requests. So include the following at the top of your file:

<script src="http://code.jquery.com/jquery-2.1.3.js"></script>

Again, we’ll create a mount point:

<div id="content"></div>

I’ll change some things around for this exercise in preparation for our next one. We’ll still deal with our PeopleList , Person , and MetaList components; however, this time, we’ll use server data.

First, I’ll expand the MetaList with a few more actions other than a “like”. We’ll hook those up in a future exercise.

var MetaList = React.createClass({ render: function() { return ( <ul className="list-meta"> <li><a href="#" className="button">Like person</a></li> <li><a href="#" className="button">Block</a></li> <li><a href="#" className="button">Ignore</a></li> </ul> ); } });

We’ll also change our Person component. This is mostly stylistic:

var Person = React.createClass({ render: function() { return ( <li className=""> <h4 className="secondary-dark"> {this.props.person.name} </h4> <p> {this.props.person.description} </p> <MetaList /> </li> ); } });

Our PeopleList will stay the same as before. I’ll put it down here anyways though:

var PeopleList = React.createClass({ render: function() { //no "ng-repeat" or "foreach" var personNodes = this.props.data.map(function(person) { return ( <Person person={person} key={person.name} /> ); }); return ( <ul className="block-list comment-block"> {personNodes} </ul> ); } });

And finally, let’s create an App component (I’ll call it People ) which will fetch our data:

var People = React.createClass({ getInitialState: function() { //set initial empty dataset return {data: []}; }, componentDidMount: function() { $.ajax({ url: '/api/users', dataType: 'json', success: function(data) { //changing state this.setState({data: data}) }.bind(this), error: function() { } }); }, render: function() { return ( <PeopleList data={this.state.data} /> ); } });

This is where the magic happens. So what’s happening? Let’s go down the function and figure it out. First, we use a new method called getInitialState . Just like render , getInitialState is a method that React will run at some specific point of time during the component’s lifecycle. render gets run when the state updates and during initial load. getInitialState gets run right before the component is inserted into the page as HTML.

The data that we return in that function will go to a new property this.state . Similar to this.props , except it’s all internal and does not get accessed by an outside entity. It’s used to manage data inside the component.

In our example, we’re just setting our state to contain an empty array called data . This is so that this.state.data is available; however, we want to fill that data out whenever we feel like it.

After the element gets rendered initially, componentDidMount will run exactly once. We’re using this to get our data. React recommends using this method to perform any initial timeout or ajax operations.

A few things about that AJAX request will look a tad funky. For instance, at the end of our success function, we added .bind(this) . That’s done so that when we refer to this within that function, we’ll actually be referring to our React component. Another way to do this is by reference like so:

var self = this; $.ajax({ //stuff, success: function(data) { self.setState({ data: data}); } })

But it’s not as nice. You’ll notice that we’re using this.setState({ data: data }) to store our data. Using setState will automatically cause the render function to re-run and subsequently update the DOM (if necessary). This is awesome since there is no digest and using an external library to fetch and manipulate data doesn’t cause the data and the component to be out of sync.

setState will extend the original this.state value, meaning that by passing in { data: data } , we’re only overwriting the data property and nothing else.

Lastly, we can pass this.state.data to the PeopleList and mount the app:

React.render( <People />, document.getElementById('content') );

Getting Data Again

Follow along with the code for this exercise.

Data is pretty useless if it’s stale and can’t be updated. This time, we’ll reorganize our People component a tad so that we can get continuously updating list of people:

var People = React.createClass({ loadPeople: function() { $.ajax({ url: '/api/users?random=true', dataType: 'json', success: function(data) { //changing state this.setState({data: data}) }.bind(this), error: function() { } }); }, getInitialState: function() { //set initial empty dataset return {data: []}; }, componentDidMount: function() { this.loadPeople(); setInterval(this.loadPeople, 2000); }, render: function() { return ( <PeopleList data={this.state.data} /> ); } });

We can create our own internal methods for our React components and as long as they don’t clash with any reserved method names (like render), they won’t cause any issues. In the example, we moved the action of getting data and setting it to the state into loadPeople which will be accessible via this.loadPeople .

I changed the componentDidMount as well to load our initial list of people and then set an interval so that every 2 seconds, the list reloads.

Here’s the catch, I set it so that we always get the list back in a semi-random order. This means that the list will should cause some kind of render action every 2 seconds (unless the list comes back identical which happens). Open up your dev console and watch the list in action. You’ll quickly discover that the parts that get re-rendered are minimal. Actually, the entire DOM structure stays in place, and only the names and descriptions of people change! If you’re using the latest version of Chrome, the parts that change will highlight for you.

In action:

>Let’s review

We’ve just learned how to use state, how to get data, and got a nice demo of React’s DOM diffing abilities. So what else was there?

Updating data in a component is very simple You can pick your own methodology to get data and use it. Since there is no $scope or $digest , outside libraries unrelated to React do not cause any issues with data synchronization and the component lifecycle

Where is X?

You’ll notice that I had to use jQuery in the example. You might be wondering, where is an http module? or an AJAX module? How about any DOM manipulation libraries? Or a router? Or X?

Angular comes packaged up with tons of features. React doesn’t. Again, React is only a view layer. Even most Flux libraries don’t solve these problems for you. But that’s okay.

It gives you an option to build your own custom stack or use VanillaJS. And the fact that React doesn’t dictate how you get data is the cherry on top.

Event handles

Follow along with the code for this exercise.

One of the last things we truly need to visit is event handling or actually interacting with our application. Brace yourselves, this is going to be a long one. We’ll build on our existing app and add tons more functionality. As before, I’ll start from the bottom-most element and work my way up to the People component.

Remember MetaList ? Let’s actually do something with it. I’d like to be able to signal if a user has already liked a Person or not. And if they have, I want them to be able to do undo that action.

var MetaList = React.createClass({ types: { like: 'like', unlike: 'like', block: 'block', unblock: 'block', follow: 'ignore', ignore: 'ignore' }, handleAction: function(e) { var state = this.state; var type = this.types[e.target.innerHTML]; state[type] = !state[type]; e.preventDefault(); this.setState(state); this.props.onActionStateChange(state); }, getInitialState: function() { //set initial state return { like: false, block: false, ignore: false }; }, render: function() { var like = this.state.like ? 'unlike' : 'like'; var block = this.state.block ? 'unblock' : 'block'; var ignore = this.state.ignore ? 'follow' : 'ignore'; return ( <ul className='list-meta"> <li><a href="#" className="button" onClick="{this.handleAction}>{like}</a></li> <li><a href="#" className="button" onClick="{this.handleAction}>{block}</a></li> <li><a href="#" className="button" onClick="{this.handleAction}>{ignore}</a></li> </ul> ); } });

A little confusing, let me explain what’s happening here. We set a default state in getInitialState to be someone who is unliked, unblocked, and not followed. Note that, I created a simple dictionary in the types object that I use to help me discern what kind of action is happening. Both like and unlike are types of a like action.

In the render method, we use the various states to show a new available action to the user. The render function will display unlike if the person was liked, unblock if they were blocked, and so on. You’ll also notice that we attached an onClick handler. This is not the onClick that you’re used to from JS. It gets compiled down to a regular event handler (a single event handle at the root of the app in fact!) owned by React. React then triggers the correct functions that we set in our components.

Finally handleAction catches the event and gets an event object passed to it. We use the e.target.innerHTML to get the current action name ( like , unlike , block , etc.), we get the current state, and we toggle its value. When we’re done, we do three more things: prevent the default action, set the new state, and send the state to a prop?

Yep, you can pass functions through props! We’ll pass the entire state to the onActionStateChange handler so that our parent component can do with that data as it pleases.

Speaking of which, let’s update the Person component:

var Person = React.createClass({ getInitialSate: function() { return { actions: { like: false, block: false, ignore: false } }; }, handleActionState: function(newState) { this.setState({ actions: newState }); }, buildClassNames: function() { var actions = this.state.actions; var classes = []; for(var action in actions) { if(actions[action]) { classes.push('person-' + action); } } return classes.join(' '); }, render: function() { var classes = this.buildClassNames(); return ( <li className={classes}> <h4 className="secondary-dark"> {this.props.person.name} </h4> <p> {this.props.person.description} </p> <MetaList onActionStateChange={this.handleActionsState} /> </li> ); } });

A few things here. We created a state that holds an actions object. Those actions mirror our MetaList ‘s state. We use those actions to create a class list via buildClassNames , a utility method. Note that you can pass a string to className .

Lastly, I created that handleActionState which sets a new value for our action object in our state and I pass that onto our MetaList via the onActionStateChange attribute.

In this example, the PeopleList will stay the same but the People component will have a slight change. Let’s look at the loadPeople method:

loadPeople: function() { $.ajax({ url: '/api/users', dataType: 'json', success: function(data) { data.sort(function(a, b) { if(a.name < b.name) { return -1; } else if(a.name > b.name) { return 1; } else { return 0; } }); } }) }

Ahh, alphabetical sorting!

> Quick Review

We’re already in a place where things are starting to get complicated. You’ll almost immediately notice that pushing data between components can be cumbersome. In fact, if we have 5 nested components, pushing that state up 5 levels means we’d have to pass around callbacks all throughout the app!

That’s just not the way to go. And can you imagine trying to access a sibling component? Again, not the best experience.

Before I explain how that can be solved, let me mention that yet again, React proves itself to be best at one thing: being a stateful view layer. Any additional functionality has to be implemented seperately. Aside from the architectectural issues, I mentioned, there are lots of tools and libs available to help you accomplish whatever you need to accomplish. Facebook keeps a handy lst of Complementary Tools you should definitely check out.

Enter…Flux

Flux is a big deal. I won’t explain how to build apps with it, I’ll save that for a “Comprehensive Beginner’s Guide to Flux” (obviously!); however, I want to look at the bird’s eye view of it.

Flux is an application architecture. That means that it is not a framework. This is confusing to a lot of people especially since Facebook came out with its own implementation of Flux called…you guessed it, Flux. But keep in mind that it’s just a pattern, a way of doing things.

So what is the core of Flux? Flux architecture is a unidirectional information and process movement. Basically, instead of having 2-way binds, everything moves in a single direction.

For instance, all the information for your entire app gets stored in, you guessed it, Stores. A Store will hold some information, let’s say, a list of people. If we have that list, it doesn’t make sense to retrieve it per component. Instead, we use an Action (another part of Flux) to get an updated list of people. That list then gets dispatched through a Dispatcher (another part), and any Store that wants that list will get it.

What’s cool is that whenever that Store updates itself, it’ll update the React View as well. And any React view that uses that store! Imagine getting that list of people, and sending that information to a PeopleList but also to a FriendList and a bunch of other components. This will sync all the components since React views are completely state/data-driven.

Now, imagine that you, as a user, liked another person on our PeopleList ; however, we have a LikedPeopleList where all the people you liked show up. When you do a like , it will send out an likePerson Action . That Action will send out that like but also retrieve a new list of people. That list will update your regular Store which has the entire list but it will also update the Store which contains all the liked people. Those stores will update all our components so both PeopleList and LikedPeopleList will be in sync!

Okay, okay. That’s a little too much but it’s exciting and it’s a natural progression in learning React so look forward to reading more about it!