ALAN XIE: Hi, everyone. My name's Alan Xie, and today I'm going to be giving a CS50 seminar on Meteor and React. We're also going to talk about a lot of other things that are related to these topics. But before I get started, I just wanted to link everyone to a GitHub repository. So if you go to this link and copy it down, this is going to be the link to all of the source code that we're going to be talking about in today's presentation. So while everyone's getting set up with that, let me just give you a brief explanation of what Meteor and React are, and why they're really interesting to use, especially for beginners, when it comes to building a web application in JavaScript. Meteor is a full stack framework that allows you to rapidly prototype things straight out of the box because it takes so many different libraries and other frameworks and links them together in a way that allows the developer to focus more on building the actual code of your application rather than the framework and structure of the application template. And what that means is, you might think a regular application, if you were to build it, if you wanted to build in some kind of real time chat communication or some other type of linkage between the client, which is what a user would see, and the server, which is where you run all of your operations, it would take a lot of effort to do that in a different framework. But in Meteor, a lot of these things are built straight out of the box. React is another JavaScript framework and it's developed by Facebook. And React is usable with a lot of other frameworks, like Meteor, MEAN, other things you may have heard of. And React is more of a paradigm than it is an actual library or framework. And what that means is, React operates in a certain way by abstracting the functionality in your application into individual components. And so if you had an application where you wanted to render some sort of information, you would abstract that particular graph into one component and that would simply be one module out of the other components in your application. When the data passed to that graph changes, React is smart enough to know that that graph should re-render or that component should re-render, and as a result your application is reactive or responsive, and is able to change itself given this type of new information. So, hopefully everyone has gotten that GitHub repository ready. If you look at the readme on that repository, it will have instructions as to how to get set up. And while people get set up, I'm also going to dive a little deeper into what these technologies are and how they operate. The final piece of the puzzle, I mentioned React and Meteor, is going to be MongoDB. MongoDB is a relatively new non-relational database. And what that means is that it doesn't adhere to the normal row/column tabular format that you would expect from a traditional database like SQL. And it gives us a lot more robustness in being able to store our data, because we can store data in a hierarchical manner. We can have one field that then has subfields, and then those subfields can have even more subfields. And this would make a lot of sense for us if we're trying to store data in a way that is hierarchical or otherwise makes more logical sense to store in a non-relational format. MongoDB might not be the best solution for you, however. And there's also some other caveats you might want to consider when it comes to Meteor and React. The advantages, as I've mentioned, are that you can build fast and deploy fast. But there are a few caveats on the scale of these technologies. The first thing is that Meteor as a framework is usually overkill for what you might be trying to build. What does that mean? Well, I mentioned Meteor has all of these packages that come out of the box and has all of this functionality built in. If you want to build a real time chat application where something that you say automatically gets sent to someone else, there's a lot of linking behind the scenes that needs to get done for that to happen. And Meteor allows you to do that relatively easily. But if you're just trying to build a blog, or you're trying to build another static web page that just displays some sort of data, then maybe Meteor is overkill because you'll have too many packages running in the background and you'll have a lot of inefficiencies when it comes to deploying your application. MongoDB might also not be right in the sense that non-relational structures like MongoDB, which are hierarchical, are always going to be more inefficient than the relational databases like SQL when you're looking to make queries on large amounts of data. And if you have millions and millions of rows of data about say, movies, you might be more interested in trying to store that data in a SQL database. So now that we've hopefully gotten an introduction to these technologies, we're going to set up our actual code base that we downloaded from GitHub. Luckily for us, Meteor automatically installs MongoDB. And we can install React as a bunch of libraries via the Meteor or node package managers at a later step. We can also install other libraries like jQuery and d3, which we can use directly in our Meteor application without much fuss. This looks like a typical Meteor or node package manager command. Don't actually run these, but this is just an example of what you would type in to install a particular package. So the first line, meteor npm install dash dash save react react-dom would install via the node package manager, npm, the node packages react and react-dom, which are the base packages for react that we're going to want to use in our application. Meteor add is the syntax for using the Meteor package manager, and all of the Meteor packages are stored online on a website called Atmosphere. And when we add Meteor packages, we identify the repository name-- in this case, mizzao-- and the actual package name, which in this case is jquery-ui. And if we type this into the command line at the directory where our Meteor project exists, we'll install this into our application. The Meteor compiler will make sure that all of the linkages are made appropriately and our application will rebuild itself and automatically reload in the browser where we currently have it running. And in this presentation, we'll be running it on localhost 3000. So if you type that into your browser, it would be localhost:3000. Well, we'll get there in a second. If you've downloaded the application from GitHub, you'll see a file directory tree that looks like this. And at first, it's going to look very daunting because if you wanted to build a very basic website, all you would really need is one HTML file, one JavaScript file if you're feeling adventurous, maybe a CSS file to do some basic styling. Here, we've got a lot of different directories that span from client to server to imports and it's very confusing because some of these even have the same name. So we'll just go through very briefly and try to figure out what's going on in each one of these folders. At the root directory, we have a client folder that's simply a boilerplate template for the basic HTML for what your application will look like. You're not actually going to write your application logic in there, but that's what's going to be actually displayed initially in your browser before you import additional components or additional JavaScript functionality that lives in the startup folder. And we'll see that the client will make a call to imports/startup/client, which is a folder elsewhere in the tree, which has some startup logic that will run on the client side of the application. I mentioned earlier that there is a client side and there is a server side when you create an application. And what that means in a more granular level is that there is some kind of logic that you want to happen only on the side of the user. So on the user's computer who is using your application. But there's other logic that you might only want to happen on your server side. If you're running sensitive data or you're managing passwords or you have API keys that are secret that you don't want to reveal to anyone, those are things you would want to operate on the server side. And these are concepts that are going to be more useful to us as we move forward. We see here that there's also a folder called dump, and this is simply a dump folder that's created by the mongodump command, which I'll explain in a second. But essentially, this is what we get when we back up a MongoDB database. And Meteor as a web application runs with MongoDB built in. And so when we want to back up our Meteor database, we run mongodump in the command line, and we get a dump folder like this. We can use this dump folder to then restore the database when we run the application. And that way in an instance like this, where we're sharing application source code files but we're not actually sharing the database, all the viewers at home can use mongorestore to restore the database from this dump and make the application work. The main bulk of your application is going to be in the imports folder. The imports folder has several main components. There's the api folder, the startup folder, and the ui folder. What's most important to focus on are the startup folder and the ui folder. The startup folder contains information that gets called by the client and by the server upon startup. So if you have information that needs to be figured out, such as you'll see accountsconfig.js, which loads our account login management system for this application, you would want to make sure that lives in the client folder. If you have security measures that you want to take place, such as rate limiting the number of calls or requests someone can make on your application, that might live in your server folder, which has a security.js file. The ui folder is the most important, because that's where each of the React components that we create will live. We have an app.jsx file in layouts, which is going to be our main body template that gets rendered into that main.html in the client folder that we saw at the top. And then we have each one of these miniature components which performs one specific function and is rendered inside of the layout app.jsx. So we have here actor_RevChart, which in this example is going to be a graph that visualizes the historical revenue of an actor, given that they're in our MongoDB database. And that component is going to be rendered in our app.jsx, and it's going to be rendered dynamically such that when we get different information from the user about which actor they want to visualize, we'll be able to get new information into actor_RevChart, and it will change itself when we call it. 00:12:09,190 --> 00:12:14,320 You might be confused why some of these files have a .js suffix, and some of these files have a .jsx file extension. And the reason for that is that when you use React components, when you use React in general, you have to make sure that the file is .jsx. And the reason for that is that React is a very special form of JavaScript that allows you to dynamically render and create HTML from within the JavaScript file. And as a result, we need to specify that extension so that we know that it's not just plain JavaScript. Now let's get started with some actual work on making our application run. Assuming that you've downloaded the zip from the GitHub repository, one of the instructions on that repository is to potentially download software called Robomongo. Robomongo is a graphic user interface that allows you to interact with the MongoDB database instance that runs every time a Meteor application is created. 00:13:39,590 --> 00:13:48,800 So what that means is when you download Robomongo, which is at this link, you can have an application that looks like this and that is able to show you in your database what types of information that you have. So you can see here in the dump that I've provided in the GitHub repository, we're able to see that we have two entries in this database of people. And in each one of these entries, we see that they have name, a profession, and a list of films. And so the actor Chris Evans, we have a list of films that he's been in ranging from Captain America all the way to Snowpiercer. And we also have here Anna Kendrick and a list of films that she's been in, ranging from Pitch Perfect to Scott Pilgrim. And we'll see that this information is going to be in our Meteor application, and when we query our application to ask for a visualization of one of these actors, this is the information that gets pulled in by Meteor and then rendered in actor_RevChart. So to set up Robomongo, what we want to do is we want to download the application, and then when you click New on Robomongo, you'll see that you have the option to create a new connection to a new database. Now I mentioned that Meteor runs MongoDB by itself, and I mentioned earlier that Meteor runs on port 3000 of your localhost. And what that means is your computer has a local server that it can run applications on. And it has a different number of ports through which that can run. Meteor runs on localhost port 3000, and Meteor's version of Robomongo runs on port 3001. So you always will know when you run Meteor in the command line that your database exists at this port. So in Robomongo, what we can do is we can create a new connection via this Create button, and we can call it whatever we want. And we want it to point at the address localhost 3001. And we click Save and then we're able to see something that looks like this. Pay attention to the sidebar where we see that we have a database called Meteor, and we have a number of collections, which are essentially sub-databases within Meteor that are organized based on the type of information in each collection. So we have one collection with people that we just saw, with Chris Evans and Anna Kendrick. We have one collection called Titles, which has information about all of the movies that these individuals are in. And we have another collection called Users, which actually stores user account login information. So what we can do if we follow the instructions on GitHub after installing Meteor, either via OS X or Windows, what we need to do is first change to the directory of cs50seminar-meteor-react, which is the folder that you've downloaded. And you want to copy and paste this set of code into your terminal. And what this does is it installs all of the React-based dependencies that you'll need for this particular repository to work and for your Meteor application to have all of the functionality that we want relating to React. So as you can see, I typed it in here, I hit Enter, and it installed this automatically. And now that it's finished installing, what I can do is run Meteor. And what you'll see happen on your computer is that if you have Meteor open already on port 3000, it may give you an error and say that you are running two copies of Meteor you're at the same time. So you can specify Meteor to run on a different port simply with the command, Meteor--port3005, to pick an arbitrary port number. And note that if you do specify another arbitrary port, that your database may end up living on that port number plus 1. So here, if I specified port 3007, what actually happens is my MongoDB instance is started by Meteor, and it runs, it will run on port 3008. So, running a Meteor application is as simple as typing in that command. And once you've typed in that command, Meteor will in the terminal, build all of the dependencies that are necessary, including the new libraries that we installed previously, and as soon as it is done successfully compiling your application and linking all of the new libraries or packages that you may have installed, it will say something down here that says, app running on localhost colon the port number that your application is running on. So while that's running, we'll look back at the GitHub instructions and we'll see one final line. We'll see here that we need to run mongorestore, as I mentioned earlier, also in the command line in this same directory, in order to make sure that our Meteor application has all of the data associated with it when you downloaded the application. On GitHub, unfortunately, the Meteor application that you downloaded doesn't come with a fully populated database, because a database is essentially something that has to run on a server. And the information on each database needs to be communicated back and forth between the individual people accessing it, or the clients. And as a result, the database must be saved in that dump directory that I mentioned earlier. And if we copy this command, mongorestore, and we paste that into our terminal, we will be essentially restoring to our database the dump file that had all of the titles, all of the people, and all of the users associated with our application. And you'll see that this command specifically restores it to port 3001. Now as we wait for our application to start we can run this. And if you've run this command twice, you might get an error that says that your collection already exists. Now we're assuming that you're approaching this with a clean installation. But there's always the potential that on your version of Meteor, that you may have run this command twice. And so what we want to do is we want to check in Robomongo whether or not these collections exist. And if they do, and we don't think that all of the information has been added correctly, we can drop these collections, which is the equivalent of deleting our database. And we can re-restore these collections back to our database with this command. And now we can see here that our application is running at localhost 3005. And as a result, we can modify this command so that we restore to the database, which lives at 3005 plus 1, or 3006. And now we see a lot of commands that have been executed, which took all of the information from our database and imported it to the database instance running on that port. And now if we go to localhost 3005 where our application lives, we'll see the Meteor application that we've downloaded. Now, there's a couple of things that are interesting for us to note. We can sign in with a default user login package that currently exists and is built into the source code. And you'll see that you can create an account or try to sign in with an existing username and password. The database that I gave you shouldn't have any users in it, so what you want to do is create an account. And if I create an account with the username alanx, password is test, I can create an account. It'll get mad at me if my password is too short. And now I have an account that's authenticated with this application. I can then sign out of my account and sign back in. And you'll notice that when I'm signed in and when I'm signed out, I see two different things. And that's a feature that in Meteor, we simply can check whether or not a user is authenticated. And if they are, we can show them different things. So in this version of the application we wanted to build, we wanted to visualize information relating to a particular actor or actress. In particular, we wanted to visualize something about Anna Kendrick or Chris Pine. We'll see here that if we type in Anna Kendrick's name, we get a graph of her revenue for all of the movies that she's been in over the past six years. If we type in Chris Evans, we'll see that the graph re-renders and we can view his filmography over a slightly longer period of time because he's made more movies over the past couple of decades. And we'll see that this is a feature of that reactivity that I was mentioning earlier where we can pass new information into this component, which is the revenue chart. And the revenue chart calls our database where we imported all of that title actor data just now. And then after calling our database, it receives some data that then we visualize using the d3 library, which is how we made this graph. So I want to go back to the PowerPoint for a second. 00:25:32,690 --> 00:25:35,340 And I want to draw your attention to some code snippets that I've pulled out of the actual source code. I've bracketed all of the important bits in a yellow rectangle for your reference. So what we're looking at here is actually HTML, but it lives in a JavaScript X file in app.jsx. And you'll remember what I mentioned earlier, that JSX is versatile in that it can dynamically render HTML using JavaScript. So we'll notice that in the top of the first of the three yellow boxes, will see that there is a special type of comment. If you're familiar with commenting in other languages, you'll notice that this is unlike the // commenting that you might get in C or in JavaScript. But here, in order to make sure that your comments register, you have to wrap the /* commenting that you might see in HTML around side other curly brackets in order for them to be properly formatted. You'll also notice in the second box that we have something called Accounts-UI wrapper. And it's simply in these brackets, and there's a slash at the end. And it's clearly not a normal HTML element. It's not a div, it's not a span, it's not a paragraph. So what is it? An Accounts-UI wrapper is actually something that we've defined in a separate file called Accounts-UI wrapper. And when we define a React component, all we have to do to call it or render it inside of our main layout is to actually just call it the same way we would a normal HTML element. So you'll notice that in this slide, the second box shows a React component called actor_RevChart, and that's the same acto_RevChart from the actor revenue chart component. And all we have to do is simply call it the same way that we would another HTML element. So one thing that's interesting is if you look at the comment on this page that's right above the first yellow rectangle, we'll see another curly bracket. We'll see something called this.state.readyToViz and a question mark. And the code here is actually a ternary condition that we use to conditionally render a particular piece of our code, based on whether or not certain criteria have been met or whether a certain state has been achieved. So we have here a state called readyToViz. And what that means is, elsewhere in our code, we've kept track of whether or not we've received the data from the MongoDB database and whether or not we've formatted it in a particular way such that we're ready to generate the graph that we saw in the application. And if we don't have the data yet, we don't necessarily want to generate a graph with no data. And so what this says is, if this.state.readyToViz is true, then we'll render everything after the question mark. But if it's false, if you look at the bottom of the screen, we'll render everything after the colon. And here, we simply have a null string, which means that if we are not readyToViz, then we simply render nothing. But when we are, we render the graph. And this is the beauty of React, in that when we change the state readyToViz, React goes through all of these different types of conditions and re-renders things that are dependent on this particular condition. And as a result, we're able to get new data passed into this revenue chart component. And we see the graph magically update with new information. Now one thing that's interesting to look at here is after RevChart has a couple of what looked like input variables going into the actual component. And the way that this works is we have one input component called data and another input property called actor. And we can store variables in session variables, which I'll explain in a second. And we can pass the session variables into this component from this parent component in app.jsx. And we will then render the revenue chart based on the different input property that it receives. So, you can imagine that elsewhere in our code we have a function that prepares the data by getting it from MongoDB and then formatting it in a particular way. And when we do that, we can store that information in a session variable, which we can then reference from inside of this call to the component via those curly brackets. We can also store information in a session variable about who is the actual person that we're visualizing. And so these are information that we pass into this child component via what are called props. And props, or properties are essentially things that we can change based on what new information or new state has been achieved elsewhere outside of this child component. 00:31:28,550 --> 00:31:32,330 One other thing I wanted to bring to your attention about how React works is that React has a series of special functions in each component that are run and that relate to the lifecycle of a React component. We talked about state and we talked about props, but what we also want to talk about is actually the mounting and updating of the component itself. And if you look at the GitHub readme, on that page there is a link to the React life cycle where you can look at this information in a little bit more detail. But essentially, there is a function that's defined for every single React component called componentWillMount. And what that does is it allows you to run some sort of logic on your web app before the actual React component is mounted onto the page. And here what we want to do is we want to run something called Meteor.call. I'll get to that in a second. But you'll see that just as we have componentWillMount, We also have component-did-mount. And component-did-mount is just as self-explanatory. It's a chunk of code that runs after your component has been mounted to the dom. And we also have additional functions such as shouldComponentUpdate, componentDidUpdate, and so on. And so at each stage of the React lifecycle, we're able to run certain logic for our component should we need it. Now, going back to Meteor.call, this is a very interesting part of the Meteor framework in that we are able to define things called methods that live on the server side of our application. And you'll recall what I mentioned about the distinction between client, which is what the user sees, and server, which is what your application runs. And on the server, we can have a function called get_names, and we can call it via Meteor.call and the name of the function that we've defined. And the server function looks like this. It's in a file under imports/startup/server/films.js. And here we're able to define in something called Meteor.methods, a function called get_names that simply takes in no arguments but loads in a local CSV file of names, presumably actor names, that are in our local project directory. And by running Meteor.call get_names, what we're able to do is we're able to conceal all of the logic in this function get_names onto a server method that the client will never see or be able to access. And so you can imagine if we wanted to do some secret stuff here, we could and no one would be able to know. And our intellectual property or our sensitive information or our secret keys would be saved here without anyone being able to see them. And after we call get_names, we have what's called a callback, which is when we call a function on the server side, it's not going to return a result instantly. And so we can't expect code that happens underneath Meteor.call to happen before the return result of get_names. And so we can pass another argument into Meteor.call, which is simply an anonymous function that has two arguments-- error and res. And what that means is that if Meteor.call fails and get_names somehow does not succeed, the result of that error will be returned in error. If Meteor.call succeeds, the result of that will be returned in res, or result. And so we'll see here that when we get the list of names from Meteor.call, we process it via res. And then we actually store it via session variable. And that allows us to access it in other components or to pass it into other components as props. 00:36:00,670 --> 00:36:03,670 Now the final piece of the puzzle that I want to draw your attention to is the actual actor_RevChart file itself. So this particular component, as you saw on the previous slide with app.jsx, is rendered in that layout and it's given a set of props that allow it to determine what particular information it should visualize. So here we have the data prop and the actor prop. And these are both props that are required by the component, and they're even specified as to the right type of prop. So if someone tries to pass into this component an actor prop that's not a string, this component will get mad at you and it will fail to render. Now we'll see that there are a couple of specific functions that are defined for actor_RevChart on top of the ones that are defined elsewhere that we've seen in the React lifecycle. ComponentDidMount we've seen before, and that's standard to the React lifecycle. ShouldComponentUpdate is something I've mentioned before that's also specific to the React lifecycle. But we have two of our own functions here called drawChart and updateChart. And these are defined here as a means of drawing the actual graph that is this component. And the way that we draw this graph is using something called d3, which is a JavaScript library that allows you to create graphs and versatile visualizations that are interactive and can also be dynamically changed and be reactive, depending on the data that you pass in. So here what we're doing in the logic of these functions is initially we draw the chart when the component is mounted using the props that we are initially given about who the actor is and what their name is. Then, shouldComponentUpdate when we get new props, we have to compare the new props to the old props to make sure that we're getting a different actor. And if we are, we call updateChart, which then redraws and transitions the original d3 graph into a new d3 graph. And we'll see a lot of the logic in here, which I've minimized for your clarity is going to be d3-specific graphing logic. So if you're interested in d3 as a visualization library to generate your own graphs, you can be very hands-on with it. And the code that you would use would be something that looks like the code in those functions. So now that we've gone over all of the individual major components of this application, let's go back to the application just for a second and try to abstract some of those concepts that we talked about into the actual execution of the application. 00:39:07,340 --> 00:39:13,750 So if we want to graph Anna Kendrick, what we have here is the user has some input that they've passed in. And in this app.jsx, we get that information and we pass that information into actor_RevChart, which is now conditionally rendered here based on whether or not it received the correct props, which it did. And you can see that if we type in something else for an actor that doesn't exist in our database, like Leonardo DiCaprio, we're not going to get anything. In fact, we're going to get an error on the back end because this query doesn't correspond to any people that our database recognizes. But if we type in Chris Evans, then we're able to once again regenerate the graph and have a new visualization be reactive to the user's response. So before I wrap up, I want to talk about some of the additional things that you might be able to do with these technologies. As I mentioned at the beginning, Meteor and React are very useful because of the incredible amount of developer support behind these communities, and also because they're so easy to use out of the box relative to other JavaScript full stack and framework solutions where you might have to do a lot of extra linking or a lot of extra work to make a lot of these functions happen by themselves. What you can do on top of Meteor and React is to build additional functionality exclusive to what you're actually trying to work on. And for me, that came in the process of taking that application that we saw, the demo that we saw, and actually building out a software as a service platform for film studios and investors to use as a means of trying to better gauge their investments on entertainment properties. And the way that I was able to do that was to build on that particular demo, which is actually the earliest version of the product that I worked on, and to then extend it with a number of other technologies that you can use side by side with Meteor, React, d3, MongoDB, all the stuff that we've talked about today. So Jupyter, for one, is a very, very strong and powerful scientific computing and data analysis version of Python where there is a lot of libraries that come bundled into the Jupyter such as numpy, scipy, pandas, scikit-learn, that allow your average user to, with very limited experience, begin to do very, very sophisticated and very high-level data processing and machine learning in Python. Now if you were to analyze movie data, thousands and thousands of different movies and the actors involved and the revenues involved, and you performed some sort of machine learning in Jupyter, what you could do next is actually try to take that machine learning and abstract that into a service where you could construct a Flask API, Flask being a mini-framework that is built in Python. And you can take all of the machine learning that you did in Jupyter and you can serve that as an API via Flask. And if you remember what I mentioned earlier about Meteor.methods where we can call APIs and we can have server side logic that the user doesn't see, you can have a Meteor application send requests to a Flask API. And at a high level, what you can do is have a user submit certain data and then perform sophisticated machine learning via the Flask API that then returns data back to Meteor for the user to see and for the user to get via a visualization. The final piece of the puzzle that glues all of this together in a production environment is AWS, or Amazon Web Services, among other web solutions that you might use. For my project development, I was able to use AWS to link Flask and Meteor and MongoDB and to appropriately install all of the servers I deployed on AWS with all of the libraries that I needed. And then I had the Meteor application in React in MongoDB communicating with Flask. And so if we go back to that very early first version of the application, something that looked like this. If you take this technology, Meteor and React, and you build on it over the course of several months, there's so much out of the box that saves you time that within months, what you can go from is this all the way to something that's much more robust and sophisticated like this. And so that's something that you can accomplish using this suite of technologies. And I hope that my talk today was informative and useful. And again, if you have any questions, please feel free to mark them on the GitHub repository or send them my way as well. I'm a teaching fellow on the website for CS50. So I hope everyone had a great time and that they learned something new.