What do you want to learn?
Skip to main content
by Samer Buna
Start CourseBookmarkAdd to Channel
Table of contents
Is This Course for You?
Hello, in this module, we'll get things started and hash out all the setup and configurations needed to work with a Full-stack React environment. And we'll do so with a simple example React application that we'll start from scratch and have it work on both the client-side and the server-side. Other than the setup and configuration, which you can skip if you're comfortable with that, we'll talk about working with data and how the structure and shape of the data influence the way to create React components. We'll cover a little bit of testing in this module, including snapshot testing, and we'll also see an example of separating components responsibilities into what makes more sense in terms of data ownership. We'll conclude this module by rendering the React application on the server and shipping an initial HTML string to the browser, and talk about the benefits of doing so.
Working with Data
In the previous clip, we downloaded some test data to work with and decided that we want to transform the arrays coming from the API into objects first. To work through the function needed to do that task, we're going to introduce a testing framework, Jest. Jest is a one-stop shop when it comes to testing. It comes ready with expectation syntax, mocks, and a powerful runner. Yarn add --dev jest, and in package.json let's add a script for the test runner, so it's jest, and we'll do --watch to start jest in watch mode and have it run the relevant tests every time we make changes. So now we can start the runner with yarn test. So we have our test data and now we want an interface on this test data. Let's create a file under lib. Call that file DataApi.js, and in here we'll design our DataApi interface. We'll make this DataApi into a class, DataApi. And we'll just export this class. In this class, we'll have two APIs, getArticles and getAuthors. Before we write any code, let's write some tests. Under the same lib directory, let's create a folder __tests__. This is one of the special locations where jest looks for tests by default. Under tests, we'll create a new file, and in here, let's match the name that we're trying to test: DataApi.js. Jest will detect this file, but I don't have any tests yet, so let's write some. The syntax here is simple. We're going to describe DataApi, and inside DataApi we're going to expect it to expose articles as an object. We're also expecting it to expose authors as an object as well. We need to import the DataApi class from up one level DataApi. We need to also import the test data, which is a property here on the file that we downloaded. So we're importing this form up one levelest data. And now we'll do the interface step. So we'll do an API constant and in here we will instantiate an object from the DataApi. And let's just pass it the test data. And let's assume the API internally is going to handle the conversion of data from arrays into objects. So, inside the exposed articles as an object test, we'll bring in the articles from the API, api.getArticles. We'll also read two things from the rawData. From the first element in data.articles, we're reading the ID and the title for that article. Now, we can do some expectations here based on that data. I'll do two expectations. The first expectation I'm expecting articles, which I'm reading from the API, to have a property of articleId, because I'm expecting the articles to be an object now instead of an array. The other expectation is to try and read the title out of this object and match it to the original title that we are seeing in the rawData. We'll do the exact same expectations for the author object, but with author data as well. So we're expecting the authors to be an object that has a property of one of the author Ids, and we're expecting this object to have the exact same properties for every author. If we save now, jest will fail, because we have not implemented anything yet. And it looks like eslint is not happy about describe and it and expect, so jest actually defined everything underlined here as global variables. So to make eslint happy about those, we need to tell it that we are using jest, and we can do that by just adding jest true here in the configuration. All these errors should go away. So now that we have failing tests for the expectations that we just designed here, we can now write our converging interface with confidence. So first I know that I'm going to get the data in the constructor here. We'll call that rawData. And in here let's just put it as an instance property rawData is rawData. Now since rawData.articles is going to be an array and rawData.authors is going to be an array, let's write a mapIntoObject function and assume that this function is going to receive an array, and this function will return the array mapped into an object and we'll go ahead and use this function, in getArticles, we're going to return this.mapIntoObject and here pass this.rawData.articles and similarly for the getAuthors we're going to map into object this.rawData.authors. We're still failing, because we have not implemented mapIntoObject. mapIntoObject is actually very simple. We can reduce the array using the reduce syntax, which gives us two things. It gives us the accumulator and the current element. And what we want to do here is we want to change the accumulator using the current element dot id and assign this ID the current element itself, and we need to return the accumulator, and the starting point for this is just an empty object. So let's test, and the tests are passing now.
Matching Data to React Components
In the previous clip tagged as 2.5, we created a DataApi class and used it to expose data collections as objects instead of arrays. We're now ready to describe a UI for that data. We'll start with the top-level App component. We'll import it here for the ReactDOM call to render App from ./App, create a new file here App.js. This is a React class component. This App component will hold the state of our application. To keep things simple, let's put both the articles and the authors object right here on the top level state of the App component, and we'll import the DataApi from up one level DataApi, and we'll import the data just like we did for the test. So data from up one level test data, and we'll do a global variable here for the API, so new DataApi from the data. In here, we get the articles with api.getArticles, and we'll get the authors with api.getAuthors. Let's just render a div here to get things to run. So I'm going to take a look at the application now. So I see the application is rendering, and the reason I'm looking at the application here is because I want to see my data. Right here, articles and authors, and every article has that and every author has that. Let me actually console.log this.state here so that we see it in the console directly. The reason I did this is because from this point on, I'm going to describe a React application to interface this data. So the shape of this data, which now I'm seeing right here in the console, is going to be the main driver for how the components are going to be structured. The interface that we want to build here is a list of articles. Whenever you're describing a list of things, you usually need at least two components, one to represent the list itself, and another to represent every item in that list. In our case, we need an ArticleList component and we also need an articleItem component inside this article list. The App component will render this article list component. To keep things simple at first, let's pass here both the articles list, which we can read from this.state.articles, and let's also pass the authors list from this.state.authors. We need to import this component, ArticleList, under components. This can be a functional component, so we'll do article list, and render a div here to hold the list of articles. This component needs to loop over the list of articles, but since we have the list as an object now, we need to loop over the object entities. We can use object.values function to get back the list of articles from props.articles. I will simply map that into an array of Article components. So in here we'll pass the Article component. The article object itself will also pass an author object, so the author here we have props.authors in this component, which is the object that holds all the authors, so we can look up the author for this article using article.authorId here. So now the Article component will receive the article object and the author object. Also don't forget to pass a key here, because this is a dynamic child, so we can use article.id here for the key. This component now depends on an Article component, so we'll go with article ./article, and we'll create article, article.js. Again, article can also be a function component here. This Article component is going to receive both the article object and the author object as part of its props, and it will render this information. We'll render the article title, so we have article.title. We'll also render date and body for the article, so date and body, and let's render the author information in here, author.first name space author.lastName, and we'll wrap the author name with an a href attribute, and the href here is going to be author.website, and inside that we'll paste the author name. Okay, if we've done everything correctly, our simple React application will actually render. I've been basing everything I do here on the shape of the data as I see it in the console log. So, let's go ahead and test. Fresh cannot find module ArticleList. Let's try to figure out that error. I totally misspelled this, so let's fix that. Test now, and all the data is coming in here.
Styling React Components
What we did so far is simple, and it works. However, let's think about components' responsibilities for a little bit. Our code makes the ArticleList component smarter than it should be. For example, the ArticleList component knows that we have an authors list. It should not. It also knows that every article object has an authorId, and that information does not really belong there. This is not about readability, it's about dependency. The way we have our code now, we depend on what this ArticleList component does with that information, and that can be avoided. The rule of thumb here is simple. Try to make the children components less smart and more of presentational components and try to have the top-level container component (like App in our case) control the logic of things like how to look up an author. An author is a property of an article, so the only component that should deal with this author property is the Article component. We violated that rule when we used the authorId attribute inside the ArticleList component. Now, take a moment and think about what can we do to improve this code into a better separation of responsibilities. Looking up one author information is an action related to a single article. So it makes sense to have the Article component do that, because it is the one who knows its authorId value. However, the App component is the one that has information about all the authors, so it is the one that can actually carry the operation of looking up an author. This is where we introduce a bridge. We write a function in the App component, and we let the Article component invoke that function. So we have an action. Let's name it lookupAuthor. We need to define this action in the App component and invoke it inside the Article component. In the future, we might have more actions, like, for example, updateRating on an article. So, let's introduce an object here in the App component to hold all of the actions. We'll call it articleActions. So this is an object, and inside that object we'll define lookupAuthor. This lookupAuthor is a function that is going to receive the authorId, and it will simply do this.state.authors, so normal lookup for that authorId. Very simple function. Now, we need to make this articleActions object available inside the Article component, so we'll need to pass it down the tree. We don't need to pass the authors list anymore, so instead, we pass articleActions, which is an object on the instance of this App component. And we'll need to do the same here in ArticleList. No more passing down the author object. Instead, we'll pass actions = props.articleActions. So, in the context of a single Article component, the property can be just actions. Now, this is slightly better for dependency, because this ArticleList component does not really know or care about what's in the articleActions object. It just relays that to its child, the Article component. If, for example, we need to change the logic of articleActions, we don't need to change the ArticleList component anymore, which is a win. Inside the Article component, instead of reading the author object from the props here, we now have actions, and we can look up the author of this article from the actions. So, actions.LookupAuthor using article.authorId. And the UI will behave exactly the same, but the components' responsibilities now are a little bit better.
Jest Snapshot Testing
So far, we created a simple React application to work with some test data. We created three components, App, ArticleList, and Article, and we talked a little bit about the components' responsibilities and how to decide on what data elements and behavior elements to pass down the components tree. However, we have not written any tests for our components. We've been testing things manually, and in the next few clips we're going to make some changes here. So without having any tests to confirm that the changes are not going to break things, we will be in the dark. So we already have jest here configured for this application, so we can simply add some tests for the components. Now there are two major types of tests we can do here; we can add normal tests, tests that will test certain logic in our code. We can also use jest snapshots testing feature. So let me show you what that means. Under the components folder, let's add the jest tests folder. We're going to start by testing the article list component. This means that we have to understand the dependency of this ArticleList component. So this article list component depends on having an article object, and inside that object it expects an object that has an ID attribute. It also expect another property, articleActions, which is another object. So we're going to fake this dependency just to smoke test this ArticleList component. So inside the test component, let's create a new file, call it articleListTest.js. I'm going to start by bringing in some dependencies. So we need React, because we're going to be rendering components. We also need the component that we're testing, so we're going to bring in the ArticleList component from up one level article list, because now we're in the tests directory. We going to also bring in the react test renderer, so import renderer from the react-test-renderer library. This is the library we're going to use to create the React components' snapshots. So bring in this as a dependency, so -- div. Now we can test. So in here again we need to bring in the test syntax, so we're going to describe the ArticleList component, and in here we want to make sure that it renders correctly. Inside the test, we use the renderer, so we do renderer.create the ArticleList component. Let me actually show you how that looks like, so let's just render a div and let's put this in a variable, call this variable element, and I'm just going to console.log that variable. Let's run jest. Now we're seeing this variable right here. It's a react test instance, so this is the actual instance of the element and it has a lot of information that I don't really need for the test. There's one thing we can do is we can convert this to JSON. So if we do toJSON it would give me the actual object representation of that element. So this is much better. This is a lot easier to test. And when we start rendering nested elements, they're all going to be inside this children property, so this is practically a tree. So now let's go back to rendering our article list, and again, I need to pass in all the dependencies of this articleList. So we figured out that this articleList depends on an articles object, and it also expects an article actions object as well. So we need to fake those for the article List, and doing that is really simple. Let's have an object here, call this testProps, and it will have articles, and in here we will just have some test data, so I'm going to do two articles, one article a and another article b. And I'll task these articles as test props to the articleList. Now every article object is required to have an ID attribute, so let's make sure that we have an ID attribute here as well. And then the other thing that the article list expects is an article action object, which has many things. Now this is going to be a full render, so it will actually render the Article components and invoke everything inside the Article components. So I need to pass in an actual lookup author here for the other component to look it up. Now we can just use a mock instead of an actual lookup author function here. We can just do jest.fn. This will give me a mock up function, and since the author component expects the lookup author function to return an object, we will return a fake object. So in here the default implementation is going to be just a fake object, just like that. And now we can pass these test properties to the article list component. So we'll just spread them here. And this will render the article list component. In fact, let's take a look. Fix this type of and it's also this here. Now we're seeing the tree, so we've got type, props, children, and I have two children, because I passed in two articles. So now we can write our expectations. The first expectation we can do is a snapshot expectation, so we're expecting the tree to match snapshot. The first time you run it, it will create a snapshot of the article list component, and every time you run it, it will just compare the new snapshot to the old snapshot. So if anything changes in the article list component or its children, then the snapshot is going to fail. So let me show you what that means. If you look under snapshot, and the snapshots, by the way, belongs to your source control, so we're going to commit that, if you look under shapshot, you'll see an actual representation of the article list component. Let's see how valuable that is. Let's say that after having this snapshot here, we went to this article list component and we want to try start refactoring things, so instead of passing an article as an object we're going to go ahead and spread this article, and the minute I save I have a failing test. So this one line added a lot of value to my tests, because I now have confirmation that my components are not rendering. So let's go back and fix that, go back to successful here. Now sometimes you'll change your component and the change will be valid. For example, let's go to article and go to the styles here and maybe change the date to be 0.8 instead of 0.85. This is a valid change. I am actually changing the mark-up of my components, so this will cause the snapchat to fail, but it will give you the exact difference of what's going on. So the font size was 8.5 and now it's 8. Do you want this to be the new snapshot? Do you want to consider this as a valid change and update the snapshot that we have on file? And if you do, you can just hit the u button, and the u button is going to update the snapshot. So now the snapshot has the 0.8 value instead of the 0.85 value. So this snapshot testing is a quick thing you can do for every component really and have a validation that the component is rendering as the previous time you rendered it. So I encourage you to always do snapshots for all the components, but snapshot is not the only thing we can test, right? We have the tree itself and we have our code that we need to test. Now, it's very important that you pick the right things to test. For example, this part here is my own code. I'm here mapping an array of articles into an array of Article components, so that's the thing I should test. I should test that the children of this article list component corresponds to whatever object I pass in. So since I passed in an object with two records, I should test that the component outputs two children, and that's really easy since I have this children attribute on the tree. So I can do something like expect the tree.children.length to be 2 and that's it. Now I have an extra test that confirms the mapping operation that I just did in the article list component.
Server-side Rendering of React Components
Working with an Asynchronous API
Before we dive into dealing with asynchronous data, I'd like to refactor a few things. We're currently in what we call a green state. We have a few tests to indicate that, green tests. But of course, in our case we don't really have very good test coverage. The more green tests we have, the greater would be our confidence to make changes to the source code, but we also have other signals indicating a green state. For example, this application rendering correctly in front of our eyes without any errors in the console, that's also another valid signal that we are in a green state. Even the fact that webpack is rendering correctly and pm-2 is not giving me any errors, these are all valid signal for my green state, so I feel confident about doing a little bit of refactoring at this point, and all of these signals combined will give me the confidence that my refactoring didn't really break things. So the first thing I'd like to refactor here is the server render file. I think this file shares a lot of similarities with the index file under the components folder. Server render renders the React application to a string while the index file here and their components render the React application to the DOM. So I think these two files belong under the same category, and that's exactly what I'm going to do. I'm going to create a new folder here, call this folder renderers, and I'll move index.js under renderers. Since index.js is the renderer for the DOM, I'm going to rename it to dom.js, and I'll also move serverRender under renderer. I'll just call it server in there. So rename it to just server. Now you'll see right away that my signals are starting to give me indicators that things are broken now, so we need to fix them. So we can actually simply use a git grep command to see where we used the server under file before. So it was only used in lib server js, so let's go there, and previously we imported the function on the same level here, so now we need to import it from lib renderers server. The index file we can grep for index and see where we used it, and we only used that in the webpack configuration file, so we'll go to webpack config. We previously indicated that the entry point for the Webpack configuration is components/Index.js, and now it's renderers/dom.js. So this should actually make the webpack renderer and the signal here happy. It doesn't look like pm2 is happy, so it cannot find that, and the reason is we are actually on the same level, so we don't need lib. Now here's the thing. This is starting to become confusing, right? I have to keep track of where I'm rendering a file from. Am I on the same level as renderer? Do I need to go up level and then close renderer? So I think the relative require in this case is not a good option. I think it's better if we can do something like start from lib, or better actually, start from renderers, because all of our code is under the lib directory. Now, when you're requiring a file from the same level, like we're requiring config here, I think relative require in that case is ok. It's a good signal that the file is on the same level, but when we start requiring files from different level, like going up one or two levels and then going down another level, this relative require becomes confusing. I think in that case an absolute level require is much cleaner, and there's actually a really easy way to do that in node. All we need to do is indicate the NODE_PATH variable before our command. So if I go to package.json here, I start my command with pm2 start, I can say something like NODE_PATH equal ./lib directory, which means all of my requires should start from under the lib directory. So let's actually test that. Let's check the status of the PM2 process. So I have a PM2 process here. I actually need to delete this process, so I'm going to do PM2 delete server. It will start a new process using our dev script that understands the NODE_PATH, so yarn dev, and let's check the logs one more time. Yarn PM2 logs, and looks like we have another error, and this error is because in server.js we are referencing a wrong path, so let's fix that under server.js, so the components folder here is no longer in the same level. So now, with the NODE_PATH configuration that I just did, I have two options: I can either go up one level, and this should work, or I can just say components/app, because the components folder is directly under the lib folder, which is my NODE_PATH. So let's check that out. PM2 is happy. It's running on 8080. What about webpack? Webpack is still not happy. So in dom.js, let's go to dom.js, cannot resolve app. Again, we are not on the same level anymore, so we'll do components app. But here's the thing. This NODE_PATH trick that we did for the PM2 process is not going to work for Webpack, because Webpack actually uses its own logic for resolving the files, but the fix is easy. In the Webpack configuration, all we need to do is add a resolve property. This resolve property is an object, and in that resolve property we define the modules property, and that's an array of all the folders that we want Webpack to use for resolving its dependencies. So now we have a new folder, and we can use path.resolve here, and my new folder that I want Webpack to resolve at is the ./lib folder, but I also need to include the node_modules folder in this case, because I am overriding the defaults. So now Webpack understands that it should look inside the lib folder and inside the node_modules folder when it encounters a require line. Let's test. Restart Webpack and there you go, things are rendering. Perfect. Let's see if the tests are passing, and they are. Let's now test that the application is rendering and it is. So what I just did is called green refactor. Basically I am refactoring a lot, but I am in the green state. I know things are working. I have plenty of signals to indicate that, so I have more confidence in the refactoring that I just did. This is important to remember: never refactor code in the red state. If you have failing tests, if you have an application that's not rendering, it's not the time for refactoring. Get the tests to pass first, no matter how bad the code that you write is to get those tests to pass. Get them to pass first. Get the application to render it. Get all the signals to give you indicators that things are working, commit that state, then refactor.
Working with a Separate State Manager
In the previous clip, which I tagged in the repo as 3.2, we've done some refactoring. One change allowed us to use absolute import paths instead of relative ones. I think this makes understanding where the files are an easier process, but it also comes with the added cost of maintaining that NODE_PATH environment variable and a webpack resolve config. However, there is one other benefit for this approach that I'd like to mention here, because I think it's relevant. It's how easy this approach makes developing your own npm packages locally. So let me show you what I mean. Let's assume we decided to maintain this DataApi.js file as its own package, knowing that we're going to be adding a lot of code here, and simply because we know we're going to need the exact same code in a different project. So we need to start a new git repo for this package. For simplicity in this course, I'm just going to manage this new package under the lib directory. Let's give it a more generic name, call it state API. And let's go in there. Now, of course I'm going to manage this package locally here just to keep things simple for this course and to keep all the code in one repo, but you can imagine that this folder can be a git submodule, for example, pointing to a separate package. Ok, so we'll take the previous code and we'll place it under state api. I'm going to create a new file. Let's actually put it under lib directory inside the state api. And we'll just place it in index.js. Exact same code. To make this state-api into its own package, we can yarn init, answer the few questions, and I'm going to make the entry point lib index.js. And we have package.json. So, the plan is to eventually publish this package. But I'm not going to do that now. We'll publish when we're ready. But here's the thing. I want my application to use this new package, and in development mode I just want my application to read directly from this state api. But when I take this project to production, I'm not going to have this state api directory. I'm just going to use the published package. All right, so I'm going to keep an eye on the tests, and I'm going to remove the previous data api, and I think we have tests here that should start failing. So let's go ahead and fix them. Everywhere we previously used data api, we now need to change it to use the new package. All right, so it looks like I'm using it in App.js. So instead of the previous up one level data api, all I need to do now is state api. And this will work locally, because of the NODE_PATH that we just did, and it will work in Production by reading state api from node_modules when we install state api as a dependency in production. This is actually really cool, because I didn't need to do any npm linking or stuff like that, and I get to grow both projects locally here in development. We need to also change the other test where we used data api, so instead of data api here, we are using state api. Just like that. And this should actually make the tests pass. So now, when we're ready, we publish this package to npm, and we push our host project to deploy without this local state api code, and things will just work because this is a normal import statement that will read from node_modules as well. Of course, before we publish this package, we should really transpile it with Babel, because it's probably a bad idea to publish an npm package that uses features that are not yet in node. So, what we do in this case, is we publish the Babel transpiled code instead of the code that we write.
Dealing with an Asynchronous API on the Client
Dealing with an Asynchronous API on the Server
Delivering the Initial Data
We need to fix two problems. We need to avoid re-fetching the data client-side, so we can't actually do all of this. We also need to avoid throwing away the initial DOM that gets mounted through the server render, and that's happening in the DOM renderer, because we're passing initialData as empty collection. So, to render the React application client-side, and have it sync with the DOM coming from the server side, we need to render the React application here with actual data. So we need access to the data here. So we can't pass an empty initialData object. Now, this initialData is something that we already fetched server-side, so we need to somehow communicate this initialData that exists server-side to the DOM renderer as well. So we can go simply fetch it from the server, but that requires a network operation. Instead of doing that, there is a simple trick that we can do. In the server renderer, instead of just exposing the initial markup, we can also expose the initial data. Let's do that. So in here I'm going to return two things. I'm going to return the initial markup, which is what I had before, but I'm also going to return the initial data, just like that. So now if I go to the server code in here, the result of waiting on the server renderer is going to be an initial content, but that's going to be an actual object. So I'm actually going to just spread this object here to have both initial markup and initial data available in the EJS template. Now I have initial markup, but I also have initial data, which I can expose with a script tag just like that. So we'll put this directly on the window object, so initial data is the initial data coming from the server variable in here. But to get this to work, we need to JSON.stringify it. This is just a requirement here in ejs, but the idea is to have the actual initial data object exposed to the client-side as a global variable. So now the client-side in here can use this initial data directly from the window objects, so window.initialData. And we can test our theory now by re-rendering the application. I see the content and I don't see any warnings from React. Why? Because now we're fetching the data once. In fact, we're delivering the data using the window object right here. You can see the data globally available on the window object and that's the exact object that the DOM renderer used to pre-render the React application and figured out that it needs to do nothing because it's the exact same markup.
Reading State from the State Manager
Now that we preload the initial data through the initial server request, we can clean up the async code that we have here in the App component. We don't need the componentDidMount, we don't need axios, and we don't need DataApi. Much cleaner. In fact, we can actually not use a state object at all. We're not changing the state, so we can totally get rid of the state object here if we want at this point, but I'm going to keep it because soon we'll introduce an action that changes this state, and we will do that through the external state manager that we started under the state-api package. So far, we've been using individual methods in the state-api package to structure the App state, but it would be ideal if the state-api package was responsible for the whole state object and we just always read it from there. So, instead of specifying articles and authors here, we just specify a data store and always read the state of the application from that store. So that is exactly what I'm going to do right now. I'm going to get rid of this initialData object. And this DataApi variable, I'm going to rename it to StateApi just for consistency. And I'm going to call this store, not just an API. So, it's exactly the same thing, but I'm going to add responsibilities to this store. So, every time we create a new object from the state-api, we get back a store that manages everything about the data. And in here, instead of passing initialData, I'm going to pass the store object, just like that. So my app only cares about the store object. I don't have initialData here anymore, but I'm going to keep an initialData concept and just pass the rawData in here. Okay, so things will not work yet, because I need to do some changes on the client side as well. So let's take a look at the client side. So the client side will now have an initialData, but it's actually the rawData, so the client side will need to do exactly the same steps. We need to initialize the store object, so in this case it will be store equal new StateApi, but this time we're reading the rawData from the window object, window.initialData, and I need to pass this store object just like I did server side. Store is store. And I also need the state-api package. So now, let's go back to the App component. Instead of manually structuring the state of the application here, we can now read it from the store object, which we're passing here as a prop. So the store object is available here as this.props.store, and I'll just assume that this store object will have a getState method that returns the whole state. So that's all the changes that I need to do in the App component. Now, let's go to the state-api package. So under index here, keep in mind that we use that with getState. So in here I'm going to go ahead and expose a getState method, and inside getState I can return an object to represent both the articles, which I can read from this.getArticles, and the authors, which I can read from this.getAuthors here. And things will actually work at this point. In fact, let's test that and see where we are. Things are working just fine, both the server side and the client-side rendering correctly without any warnings from React. However, if I'm going to read this state multiple times, this means that I'm going to be returning this object and basically doing the conversion that I do inside getArticles and getAuthors every time I read the state. So that's actually not ideal. So let's fix that. Instead of managing rawData here, I'm going to go ahead and manage this.data, the actual data object that I'm going to expose. And this data object will have articles and I'll compute the value of these articles right here inside the constructor, so this .mapIntoObject from rawData.articles. I'll do exactly the same for the authors property, so authors to be computed from inside the map into object. This means I don't really need to expose getArticles and getAuthors object now, because I'm always exposing getState method, and the getState method can simply return this.data. So, what we have is equivalent, but now every time I read the state, I'm reading the exact same variable and I'm not doing the computation every time. I think this is better. Make sure things are still rendering, and they are. Let me rename this into state-api again for consistency. And now since I have a state-api object that manages the state of the application, I can always read from there. So, for example, in the App component, I previously had a lookupAuthor object that I had to pass down to the Article component to look up an author. But now I can do this thing inside my state manager, so I'm going to kill this part here, I don't need it anymore, and inside the state-api, we can define lookupAuthor directly here. So this is going to take an authorId, and it will simply return this.data.authors for the passed-in authorId. So exactly the same logic, but now inside this state-api. Let me actually change those into class properties so that we don't have to deal with any binding. So getState is a Class Property here and it's using Arrow functions. So now if we go back to the App component, I don't need to pass articleActions down to the Article component. Instead, I can pass the store itself, because I have the look up author defined on the store itself. So look how much we're simplifying this App component now. Instead of articleActions, I'm going to pass store, which is part of the props of the component here. So this.props.store. And in articleList I need to do the same. Instead of passing actions, I'll just pass the store itself, so the store is now a property here, store, and inside the Article component, instead of reading the actions here, I'm going to go ahead and read the store. And the lookup author is part of the store API, just like that. And I think this should work as well, and it is working. It's rendering both server-side and client-side exactly the same, but now I have one manager of this state, this state API class from which I created the store object, and it manages the state. It manages the initial shape of the state, it manages any functions I need from that state. That made my React application much simpler. The React application depends on the store for reading the initial state. It also depends on the store for passing down some actions all the way to the Article component and looking up the author from this store here directly. However, to get this to work, I had to pass the store object to all the components, including this ArticleList component, which really did not care about the store. What do you think we can do to make that better? How can we make the Article component access the store, because it needs to, but without having the ArticleList component pass the store as a prop? Because again, the ArticleList component does not really need to be even aware of the existence of a store object. Think about that, and in the next module we'll talk about it. But before we go there, I think the changes that we made here probably broke the few tests that we have. Let's fix those. The first test is in the snapshot of the ArticleList component. Previously, we had article actions, now we have store, and it's actually the exact same signature. And the other failing tests is for the DataApi itself. So let's take a look at that and their tests DataApi. We are still reading getArticles here, so I'm going to go ahead and rename this as state-api for consistency, and I'll rename this as store. Now, instead of getArticles, I need to do getState, which is a function, and then read the articles from there. And same thing for the authors. Instead of getAuthors I need to do to getState, and then read the authors from there. So that should make them pass.
In this module, we made the React application work with data coming from an asynchronous API. We started things out by refactoring the state manager into its own node package. We then saw how if we made the client fetch the initial data, we would need to make an unnecessary second fetch on the server. So instead of doing that, we made a single Ajax fetch on the server, made the server expose both initial markup and initial data, and used the state manager as a store to manage the state on the client side, feeding the state the initial data as exposed by the server on the initial request. But so far, we have not changed the state. We are ready to do that next. In the next module, we'll introduce a few concepts like the Context API, which everyone will tell you not to use, and the concept of higher order components, which are getting really popular among the React community.
The Context API and Higher Order Components
Type-checking with PropTypes
React's Context API
In the previous module, we introduced the store object to manage the state of this application, and we added a lookupAuthor method on that object. We needed to use this lookupAuthor method in the Article component, so we had to pass down the store object from the App component to the Article component, passing it through the ArticleList component as well. However, the ArticleList component didn't really need this store object. The question was, how can we make the ArticleComponent use the store object without having the ArticleList component deal with it? The answer is simply make it into a global variable, but since this store object is associated with an instance of the App component, we need a global object associated with that instance. React has a solution for that. It's the powerful Context API. The React documentation warns about using the Context API, for good reasons. The context object is after all a global concept, and anything global should be avoided if possible. However, I think it's important to understand the context API, especially if you're using a library that uses it, like Redux or React Router. So I'll show you how to use the Context API, and I'll then tell you what libraries like Redux do to make you avoid the direct use of the Context API, which the React documentation warns that it's not stable and might change. So, the goal is, we want the application to continue to work, without this line here in the ArticleList component. Removing this line will break the application. Here's how we can use the context API to fix that. In the App component, we need to define the context object. We do that with a getChildContext function. Whatever we return from this function will be our context object, so we're going to return the store, which is a property on this App component. So this.props.store. Just like that. Now, to make the contexts API work, we need to define the context type. We do that with a static property here in the App component, childContextTypes. For every element of this new context that we're introducing, we have to specify a type. So the store, for example, is an object. So we can use the prop-types library to do that. PropTypes.object. Of course, we need to import prop-types, and that's it. That's all we need to do to make the store part of the context API, which can be globally available to any component within the React application. Now, for every component that needs to use this context, like, for example, the Article component, we also need to define the context types here. So article.contextTypes, very similar to propTypes. And in here we define that the store is an object using the prop-types library as well. And just by doing so, we declare that this Article component is allowed to use this context object, which has the store object globally defined on it. So a function component can access the context object using its second argument here. So the first argument is the props and the second argument is the context. And now, instead of reading the store from the props, we can read it directly from the context. So context.store. Let's make sure that things are rendering, and looks like they are. So let's review this really powerful context API. We define a getChildContext function. In that function, we return exactly the context object that we want to be globally available for every component. In our case, we just defined the store. We also have to define the context types. In here, we do childContextTypes and we define the type of every element on that context. Then, inside the component we also define what types from the context that we want to access, and then in the second argument for a function component, we can access the context. We can actually de-structure the story here directly if you want to, which would allow us to just use it directly here as well.
Shallow Rendering with Enzyme
The changes that we made to how to access the store broke the tests. Let's run them and press a to run all the tests. Now we have one failing test, which is the article list render. You'll see in the output here that we're now getting warnings about the proptypes. Remember that we added proptypes validation. So this is actually just a warning, but the actual error is that the lookup author method is no longer defined inside the Article component, and the reason is previously we passed the store down to the Article component from the article list component, and now we are reading the store globally. So this part here is no longer valid, and to get this test to work, since I'm not testing an App component here, I have to fake this now global context object to make the Article component render correctly. So that powerful context API that we just used is making testing of components much harder, because now we have a global dependency. And this is happening because the renderer here is a tree renderer. It renders the full tree, so when I say render the article list, it will start from the article list component and render that, and then it will actually render every child component inside that article list component. Now we can do a few things here. We can either adopt an integration testing approach, which means pass actual data to the component and try to fake the context of the store. This is probably a good strategy to test the top level component, but for components below that, I think a unit testing strategy is much better. So let me tell you what that means. With a unit testing mentality, the point of this test here is to test the article list component, not the Article component. And React has a concept to do that. Instead of tree rendering, we can use shallow rendering. Shallow rendering will only render the article list component, and then for every article inside the article list component, it will just have a stub that in here there will be an article. Now, the react-test-renderer actually support shallow rendering, but there is a much better library to work with shallow rendering. It's called Enzyme from Airbnb. This tool actually enriches the React built-in testing utilities with much better syntax. For example, it adopts a syntax similar to jQuery for finding elements in the DOM, which is really cool, but we're going to use it here for its shallow rendering capabilities. So this is going to be a dependency. We need to yarn add --div enzyme, and instead of the react test renderer, we're going to import the shallow function from enzyme. Ok, so the article list component still expects an articles object like that. There is no longer store, so I can remove this from the test props, and instead of rendering a tree, we're going to render what's commonly named as wrapper. So instead of renderer.create, we can just call this shallow function. We don't need to convert things to JSON. So I'm going to comment out this part and take a look at what this wrapper look like. It's a shallow wrapper object, so for example, we can do something like wrapper.node.props.children. Take a look at that, and you see that this is the array of the rendered articles. So the syntax is a little bit different now. So instead of the previous tree.children now we can do something like wrapper.node.props.children.length. Let's actually make sure that this is going to pass, and it looks like it is passing. So I'm going to remove this console log, and I can actually just expect the wrapper itself to match the snapshot. Enzyme support that. However our snapshot is actually different now. So previously we were rendering actual articles, and now with the shallow wrapper we are not rendering the articles. So you'll see inside the shallow render output that this is where we're going to render an article, but we're not really actually rendering an article. So this is perfect. I can update the snapshot now, and it's going to pass, and if you take a look at the snapshot now, you'll see how it is not rendering every article and just putting an Article component to be rendered here. However, I still see the prop type validation firing, which actually surprises me, I wouldn't expect Enzyme to invoke the prop type validation, because it's only shallow rendering the article list component, not the article. So there might be a bug here somewhere that's causing Enzyme to invoke the prop types of an article and it shouldn't. But if I want to work around it, I can simply import the Article component here, so import article from up one level article, and I can fake the prop types of the Article components. So article.proptypes equal an empty object, and that should remove the warning. So let's keep this syntax for now. So enzyme really has a lot of features. For example, instead of wrapper.node.props.children, I can, for example, do something like wrapper.find Article, and that should also be two. So this find syntax really is a convenient way of locating elements rendered within a component instead of depending on the shape of the tree, which is really cool.
Presentational Components and Container Components
Let's take another look at the Article component. It now uses the context object to access the store. We've seen how introducing this global context object made testing things harder. If, for example, we want to test this Article component now, we have to fake a context object. We can't even shallow render this component without that. This is one other reason why we should consider a different approach. One thing we can do is to split this Article component into two, one component is responsible for extracting the store out of the context API, and another responsible for rendering an article object. A component that does anything beside presenting UI is popularly known as a container component. So basically, we'll consider this Article component here the presentational component, and then we'll create another component, call it article container. This is also a function component. And this component is going to be responsible for extracting the store out of the context. So the signature is the same, props and store out of context. And now, from within the article container component, we simply return the Article component, and we'll copy the props. The exact same props. Just like that. So this is a pure container component. Now we have the option of passing the, for example, store as a property to the Article component directly from the context here. Because this here will be context object, so I am destructuring the store out of that and now I am passing the store as a property, which means in the Article component I don't need to access the context anymore. I can read the store from the props. We can read it from here. This also means that I don't need the context types on the Article component anymore. I just need it on the article container component, just like that. So let me move this part next to this part, and I need to export the article container in this case, because that's what I need to use, and now I have two separate components. A presentational component, which is easier to test now that it doesn't depend on a context object, and the container component, with the only purpose of being responsible for extracting the store out of the context object. So, this is much better already, but we can go one step further. We can actually make this article container component a generic one. Say, for example, that we want to access a store from other components. Instead of duplicating this container logic per component, we can create a generic function that generates a container component responsible for extracting the store out of the context object. That function is what's popularly known as higher order component.
Higher Order Components
We're about to create a generic function that generates a container component to provide any component with the store object without having it deal directly with the context API. Since we're providing a store here, I'm going to call it the storeProvider and I'll just place it here on the same level as the Article component. So we're going to remove this article container component logic and instead assume that the article container is going to be generated using the storeProvider function. Now, this function will need to know which component it's providing for, so we'll pass the Article component as its only argument here. In fact, we can simply just have this function call here as the default export here directly. Let's now create storeProvider, so under components, storeProvider. So this is going to be a simple function, storeProvider. This function is going to receive a certain component, and it will basically create a container component and return that. So let's do that. Let's create a new component. I'm just going to call it WithStore. It's a function component, so it will have props and it will have the store object destructured out of the context argument, and this WithStore component is going to render our original component with the props copied out and the store passed as a property directly to the original component. And of course, since this WithStore component accesses the context API, we need to define the context types here, which are basically what we had before, so store is a PropTypes.object, and I'm already using both React, so import React, and prop-types as well. And this storeProvider is going to simply return with store. And I need to export this storeProvider function. That's basically it. This is the simplest higher-order component function. It's a function that would receive a regular React component. It will wrap it with a new component. We call this component WithStore, and this wrapper component will have some other logic like, for example in our case, it is fetching the store out of the context API and providing the store to the original component as a prop. So at this point, we should test things out. So make sure the application is rendering, and it's still rendering. So now if you inspect the tree of the application, you'll see that the ArticleList component actually renders the WithStore component, and every WithStore component has the store context API, and it renders an Article component and that Article component only gets props. So our contained Article component is now a pure presentational component and the WithStore component is the container component. And it's the only one that is accessing the context API, and it's a generic one. So say, for example, I needed the store in the ArticleList component, I can also have it wrapped with this storeProvider function that generates a component. It's usually a good practice to have the name of this container component related to the component that it contains, and we can easily do that using the React displayName property, so we can do something like WithStore.displayName is, for example, we can do the original component name and Container. So we'll be back to, for example, ArticleContainer or any other component container. Let's test that. So I've got App, ArticleList and then ArticleContainer. And now every time I provide the store, I'll get a container component that wraps an original component and pass down the store as a prop. Now, usually when we create higher-order components, we don't use function components, we use class components. Because usually a higher-order component is going to manage some kind of state and maybe need some component lifecycle method. So instead of function component, we can simply use a class component, so I'm going to return class extends React.Component, and with a class component we do things a bit differently. So we can use static properties for the display name, and also for the context types, and after that we need to define the render function, which is going to return the exact same thing that we have here. So component passing in the props in the store. However, in a class component we need to do this.props, and we need to read the context from this.context.store. So this would be exactly equivalent, but now using a class component instead of a function component, and now we can manage the state if we need to, and we can use lifecycle methods as well. I forgot a return statement here. Let's test and make sure things are still working, and I'm seeing the article container component wrapping Article components. There is one other small fix that we need to do. The tests are now failing, and they're failing basically on this line, because previously we were trying to find the Article component in the shallow rendered output, and right now a shallow rendered article list component will only have article container components. It will not see the Article components at all. So we need to simply change this into article container, and at this point I can actually remove our previous hack for the prop types on an article, because the Article component is not included at all in the shallow rendered output of the article list component. So if we run the tests now, this part should pass. However, we still need to update our snapshots, because it's now rendering article containers and not articles, so we'll just do that.
Mapping Extra Props
The Article component is now a contained one, which takes it further into the presentational direction, but one can argue that it still depends on the store API here by calling the lookupAuthor method directly from the store object. It would be ideal if we can extract this logic as well and have it maintained by a different entity. Since we now have a storeProvider function that basically renders this article with the same props, we can have this function also pass extra props. Just like we did with the store, we can have it pass the author directly. So I want to basically remove this line and also remove the store constant here, and just assume that the author object is coming from the props as well. Now, this author logic needs two things to be invoked, a store and an article, which is part of the original props. So I can basically have a function that applies to exactly these two things, the store, and the originalProps of the wrapped component, and I'll make this function return a simple object with the new props that I want this Article component to have. So, that'll be the author, which is coming from a call to store.lookupAuthor for the originalProps.article.authorId. So, a good name for this function would be extraProps. Now, since the storeProvider has access to both the originalProps and the store object, all we need to do is have the storeProvider invoke this extraProps function and make its returned object part of the props that it uses on the wrapped Article component. We'll use a functional programming trick to pass the extraProps function to the storeProvider. We'll make storeProvider a function that returns another function, and pass extraProps to the first function, and keep the wrapped component as the argument for the second function. So in storeProvider, it'll now be a function that returns another function. Arrow functions make this really easy to write, and now this first function will have access to an extraProps function as an argument. And in here, when we render the original component, we'll also pass a new set of props. We'll spread the extraProps function called using the store object, which is part of the context here, so this.context.store, and the original props, which in here would be just this.props. Just like that. And that's it. Things should actually work at this point, exactly as they do. But if you take a look at the tree now, you'll see that the article container component passed down both article and author. It also passed down the store, which I didn't really use here, but I'll leave it in case some other component needs extra control over the store object. So this storeProvider function is now a customizable higher order component, because it can accept a generic function, extraProps, that we can use in any component to isolate any props logic that depends on the store, which leaves the wrapped component as a pure presentational one that only receives normal props and present a UI for them. If you've used the React Redux bindings before, this should look familiar, because it's similar to what the connect function in that library does. This is now a recognized, good pattern to do when you need components to access things out of the Context API because it isolates that access into just one function instead of different individual components accessing the Context API on their own.
In this module, we covered a few different topics to improve the React application that we're writing. We first talked about validating components props using the PropTypes package, and we used that to make sure every article object that we pass to an Article component has the right shape. We then explored React's powerful context API and how it can be used to pass React-application-scoped global variable to any component in the tree. We used the context object to give children components access to the store object. Using the context API made testing things a bit harder, so we talked about ways around that and one of them is shallow rendering and we used the Enzyme package to do that. One simple trick when working with the context API is to split a component into two. Leave one component purely a presentational one that maps data to UI, and have another component that contains the presentational one and perform any non-presentational logic like accessing the context API, for example. Using a higher order component function, we can make the presentational to container relation a generic one that allows us to wrap any presentational component with a context-fetching container component. We can also customize this container component to provide extra props, which allowed us to further extract any logic that depends on the global context out of the presentational components and into a separate function that is testable on its own. So far, we've been only reading static values from an initial state. It's time to start thinking about what happens when the state which is managed outside of the React application changes.
Subscribing to State
Using the setState Function
Let's put a few things on the state. We'll start with a search component that filters the displayed articles. Let's create a new component for that. I'm going to call it search bar, and it's a regular React component. And we'll make it return an input element. I'll give it a type search. And let's also put a placeholder, something like Enter search term, closing tag. And to render this component, we'll include it in the App in here. So we'll import search bar and we'll include it in the rendered output in here, search bar. Of course we can't just return two components like this. So we have two options. In React 16, actually we can return an array, just like that, instead of just one element. And of course if you want to return an array, we have to give each element a key attribute. So this is a good option, if the rendered output is generated with an array. But for a simple list of component like this case, I'd rather just return a div. So we'll make this component return a div. And we'll make that div include the two components. And we can test that, make sure that search bar renders. And it does. So now we want to type something in here and filter the list as we type. This means after we're done typing, we want to put this search term on the state, so that the App component gets to filter the list of articles based on that search term. So in the search bar component, we'll do something like onChange, go ahead and handle search. We'll put that as a handle search function on the component instance, and we'll define that handle search function. And basically I want to first console.log the value of the input. Now we have a few options to extract the value of the input as a user type. The first option is to define a ref attribute in here. This ref attribute takes in a function, and this function exposes the input element itself as we type, so we can place something like this.searchInput is that input element that the function exposes. And in here we can access the value the user types with this.searchInput.value, pretty simple. Let's actually test that. So hello, and you'll see that we access the value as the user types. The other option, and the more recommended option, is to put the value the user types on the component state itself. So instead of doing a ref attribute in here, we'll define a state property here for the component, and on that state let's put a search term, which starts as empty string, and we'll control the value of this input element through this new state property, so this.state.searchterm. So this makes the component a controlled one, because the value is being controlled by React. But onChange we need to update the state of this search term, this handle search function receives the event itself, and we can do something like this.setState every time the user types. We'll go ahead and set the search term to be the event.target, which is the input element, .value, and to access this search term, we can simply read it from the state, so this.state.searchTerm. So let's go ahead and test that. Now when we type, not only do we get the value here, but React is also aware of this search term. So if we inspect this search bar component, we'll see that the search term is now managed through the state of the search bar component. So this is a more preferable option to get the input from the user, because this way the search bar component will be aware of the state change that happened in the UI. But now after we type a term, just like that, we need to make the App component aware of this search term, because the App component is the one that's going to filter the list of articles. However, instead of filtering the article on every character typed, we should filter it when the user is done typing. So instead of doing a filter on h, we'll do a filter on just hello, which means that we need to debounce the action of making the App component aware of that state. So we can actually test this debouncing feature before we go the App component. So after we set the state, we want a function that debounce the action of submitting the state to the component. If you want to do something after we set the state, in React we have to use the second argument for setState, which is a callback that gets invoked after the state operation is done. So the debounce operation should go here. So you can simply use the debounce function from the excellent lodash libraries. So we'll import debounce from lodash.debounce, just like that. So when we import it this way, lodash.debounce, that means that we're not really importing the whole lodash library, we're just importing the debounce function from the lodash library. This is a dependency, however, so we want to yarn add lodash.debounce. So let's define a component function here. Let's call it doSearch, and this function is going to be debounced, so this function is a debounced version. And we'll go ahead and test it with just a console.log statement, so console.log. And I'm going to read this.state.searchTerm in here, and we'll debounce this after a delay of 300 milliseconds. And inside the setState, we'll just invoke doSearch, so this.doSearch. And we can go ahead and test that. My expectation would be, as I type, this handle search is going to set the state, and it's going to invoke a debounce function, which means I'm not going to see the console.log statement, until I pause for 300 milliseconds. So we can go ahead and test that. And I'm going to type in hello. And you can see that only hello was console logged, so not every character I typed. And this works if I hit backspace as well, you'll see an empty string. So we can assume that this component is going to receive the do search operation from the App component, because the App component needs to be aware of this search term. So we can simply assume that the function name would be also doSearch. So in here, instead of console logging the term, we'll do this.props.doSearch. So the component receives a doSearch function, and it will debounce it locally here, and call this locally debounce function inside the callback of the setState component. So now in the App component, we'll have to pass a doSearch operation here to the search bar component. And in here, we'll call it locally this.setSearchTerm, so set search term will be a function that receives the search term. So it receives search term, and we can simply just use this.setState and put the search term in here. So now when we type in the local search bar component, it will invoke this function and this function is going to set the search term on the state of the App component. And now the App component can go ahead and use this search term to filter the list of articles. So we can test that. Basically my expectation here, as I type a full word and pause for 300 milliseconds, I should see a search term on the state of the App component. So let's go ahead and verify that. And we see a search term on the state of the App component. And if we clear the search term, the search term is going to be cleared on the state of the App component. However, in here we were initially reading the states from the store, and now we're locally changing the state of the App component. So we're going to fix that next. But for the App component to actually use the search term, we should probably also initialize it as an empty string in the store. So we'll go to the store, and in here the initial data will also set search term to be an empty string. So now in the App component all we need to do is filter the list of articles according to the search term. So in here we'll do something like, let articles = this.state.articles. And if there is a search term, we need to filter the list of articles. Now the list of articles here is an object. So there is no built in filter operation for an object. So if we want to filter it, we have to filter it through an array and convert the array back into object. But the lodash library has an excellent function that can help us with that. It's called pickBy. So we'll import that, so pickBy from lodash.pickBy. And this is a dependency, so yarn add lodash.pickBy. And using pickBy is really simple. We'll just do articles here = pickBy, and this pickby has two arguments. So the first argument is the object that you want to filter, and the second argument is a function. And this function receives both the key and value for every item in the object. And we want to return true if we want to pick that item. So since we want to search for the value title and description, we can do something like value.title.match, the searchterm. Or value.body.match, searchterm. Of course, I need to read the search term out of the states, so we'll go ahead and destructure both articles and search term from the state object. And now instead of using this.state.articles in here, we'll use the articles variable, which could be filtered based on the search term. I think we can test that. So we'll go ahead and do some search. Looks like we have an error, cannot read property match of undefined. So actually pickBy receives the value first and then the key. And we're not really using the key, so we can actually skip that. Let's test now and go ahead and search for better. And looks like it's working. So we now have something on the state. But again we set the state locally, so now the store is not really aware of this search term. So in the next clip we'll fix that problem. And always read the state from the store and have the store itself aware of any state changes.
Subscribing to an External State
We're now writing to the state through the React setState method. However, we previously read the state from the store. The React built-in setState method is usually good enough if you have a very small state and you don't have a lot of actions on this state object. However when the state gets bigger, it's usually a good idea to manage the state separately from the React application, so that you don't have a lot of logic in one React component. And that's exactly what we're going to do, because we previously read the states from the store. So the idea is we're going to make this store object responsible for everything state. And the App component will always just read from the store object. So my goal is to move these three lines into the store. So we'll comment them out here, and I'll put them in the state API index .js, set search term. And now this store doesn't have a setState method, because, well, this setState method is coming from React, so we'll come back to this part and implement it somehow in the store. But once we have a set search term, we can call it directly here. So basically instead of all this, we can actually call set search term directly from the store, so this.props.store.setSearchTerm, and this way the store object is going to be aware of this search term, and I'm not managing the state in the React component at all. So we'll go ahead and implement set search term. So this store manages add data property, and it just returns that property. So I need to set the search term here. So this is super simple, we can just do this.data.searchterm = searchterm. However once we do that, we have a disconnection between the App component and the store, because we are changing the data in the store object; however, the App component reads the state out of the store object only when it gets constructed. So we basically need this React component to update when the store state changes. And we have a few options to do that, but the idea is that we need to subscribe to store changes, and by subscribe I mean provide the store object a callback to be executed every time that store object changes its data. We can implement this in a lot of ways. So for example, we can make this state API an event emitter, and every time we change the state, we can do something like this.emit a change event. And we can make the App component add a listener to this change event emitter and invoke a callback then. This is actually the core of the flux pattern in React applications if you're just using a vanilla flux implementation. A flux store isn't an event emitter, just like that. However the simpler choice, is how the Redux library does that, which is basically to manage subscription in the same object. And when it's time to notify subscribers, we just loop over them. So this is simple, let's do that. We'll manage subscribers in a variable on the instance here. Let's just call it subscriptions and we can manage that with an object, so every time anybody subscribes the store will just place it their subscription on that object. And we're going to need an ID to identify every subscription, so we'll do last subscription ID and we'll start that with one, so every time we subscribe a user we're going to increment that subscription ID. So we basically need two methods here on the store object. We first need a subscribe method, so every component that needs to subscribe to the state of this store it's going to call this method so this would be a function and it receives a callback. I'll talk about that in a little bit. But we also need to unsubscribe, so every component that subscribe should also be able to unsubscribe somehow. Right? When we unmount the component we should unsubscribe, because this is an active listener, so if the component gets unmounted, we don't want this listener to exist anymore. So subscription is easy. We basically want to add an element to this.subscription, so this.subscription, and we'll use this.lastSubscriptionId, and we just place the callback function on that. So the value for the subscription is just the callback function. So the callback function is what the subscriber is interested to be executed, so basically when I subscribe to something I provide a callback function, and that means that I'm interested in your data change and every time that data changes you should invoke this callback. So I'm going to go ahead and increment this.lastSubscriptionID for the next one. In fact, let me actually increment it before, so that we get to return the subscription ID. We can start that from zero so that we have one as the first subscription ID, and I'll just return this.lastSubscriptionID. And the reason I'm returning this.lastSubscriptionID is so that I enable the unsubscribe to the subscriptionID, so the unsubscribe will have a subscription ID in here. And it will just simply delete this.subscriptions for that subscription ID. Very simple. So to subscribe to the store, you just call the subscribe method with a callback function to be executed when the data changes. And to unsubscribe, when you subscribe you get a subscription ID and you can unsubscribe by calling the unsubscribe method with that subscription ID. So let's go ahead and subscribe to this store from the App component. We can do that in componentDidMount. So basically in componentDidMount, once we have a component, we'll go ahead and do this.props.store.subscribe, and we want to pass a callback here. Right? And this is going to give us a subscription ID, right? So we can actually place that on the instance like that so that we access it in component will unmount. So now in component will unmount, we will just do this.props.store.unsubscribe using this.subscriptionID. So this is very simple, we just subscribe to the store, we get back a subscription ID and when we unmount the component we just unsubscribe. However, we need to know what to do here. Right? In here, what are we going to do? So the App component subscription basically needs to update the component State, the React internal state, every time the store state changes, because we want to keep both of these in sync. So we'll create a new method. We'll call this method onStoreChange. This method is local here, so we can do something like this.setState and we can read the state from the store. So again, this.props.store.getState, just like that. And we can pass this on store change to the subscribe as a callback, so we'll do this.onStoreChange. So basically what I'm doing here is that I'm expressing interest in the store state and I'd like the store to execute this callback every time its data changes. This way the App components state will be completely in sync with the store's State. So I get to manage the state in a store object externally to the App component, and I get to reflect those changes to the App component to get my React application to update when it needs to. Okay, so now all we need to do to finish this feature is basically to notify all subscribers. So every time a subscriber subscribes, we're going to put them on this subscription object. So when we do any data change, like this line, we need to notify all subscribers basically. So let's create a new method here and call this method notifySubscribers, and this is a very simple method. We'll basically need to loop over this.subscriptions, which is an object, so we'll simply do object.values, and we get all the callbacks we're going to loop over these callbacks. And for each callback, we'll get access to that callback here, so the value here is the callback. And we want to simply execute that callback, just like that. So loop over all the subscription values, which are callback functions. And for each one of them, just execute it. So now, every time we do a change like that, we want to call notify subscribers, just like that, this.notifySubscribers. So I think at this point we can actually test. Let's do that. So we'll re-render an application, make sure we don't see any errors, and try to search. And looks like it's working. Here's what's happening, when I typed the letter here, the state of the store itself has changed. So I can highlight this and inspect it $r.props.store.getState, and you'll see that the search term is set on the state of the store. However my React application rendered because I subscribed to that store. So every time we set the search term, we're going to notify all subscribers. So possibly more than one component is going to subscribe to the same store. So when we do a data change, when we do a state change, we want to notify all subscribers. However we will probably change more than just the search term on the state. So every time we change the state of the store component here, we need to notify subscribers. So it's probably a good idea to have a method that changes the state and just call that method all the time. So we can, for example, instead of notify subscribers here, and instead of setting the data here, we can think about calling this method. We do something like this dot maybe, I'm going to call it merge with state. And the reason I called it merge with state is because I'm going to pass in this search term, just like that. And I want this search term object to be merged with the state that I have originally, and I don't need to call notify subscribers, because merge with state is going to do that. So merge with state is a function. This function receives a value, let's call this value state change. And what I'm going to do is I'm going to merge it with the state, so we'll do this.data = the original data, and then my states change, just like that. So basically copy the original data and then merge the state change objects that I pass. And after I do that I can notify subscribers. So now every time I want to do any change, I do it just through this merge with state function that's going to generically do that operation and notify all the subscribers. And this way I'll have just one call to notify subscribers, I don't have to do it every time I do a change to the state, as long as I do the change through the merge with state function. Let's go ahead and test this change as well. Refresh, search for something. And looks like things are working.
Passing State to Child Components
Now that we have a state that we can subscribe to, I'm going to go ahead and introduce another component that subscribes to this state. So how about we display the current timestamp and make it tick every second. So I'll go ahead and do that, let's add a new component here, we'll call this component timestamp.js, and it's a regular class component, and I'm going to call it timestamp. So we can actually subscribe to the state directly here or we can pass the time to the component as a prop. I'm going to go ahead and pass the time to this component as a prop, so basically in the App component we will import timestamp. And I'm going to include it here right before the search bar, and this component is going to receive the timestamp value, so basically it will have a timestamp value that it's going to read from the state, so this.state.timestamp. And we'll just go ahead and render this timestamp in the timestamp component, so in here we'll just render it in a div, so render this.props.timestamp. Now I don't have a timestamp property on the state, so that's something that I need to initialize. And we'll initialize it in the store. So in the store in here, we need a timestamp property, and we can initialize it with new date. And I think we can test that, so refresh. And looks like I have an error. So what's going on here? So, objects are not valid as React child, that's because we rendered the timestamp here directly. We can tostring that, and I think that will work. So let's go ahead and test that. And I have the timestamp. Of course, the timestamp is not ticking, because I didn't change it on the state. So we'll do that next. So we can do that in the store itself. Basically in here we can setInterval, and inside the setInterval, we'll do something every one second, and in here it will just do this.merge with state a new timestamp object that is basically a new date, just like that. And I think that should work. So let's go ahead and test that. And it looks like the time is ticking right there. Now I'm getting a warning here, React attempted to reuse markup, which tells me that the server rendered output is different than the client rendered output. And let's think about that. So we have a new date and then the interval is going to kick and change that. So basically this is probably happening before the component mounts and the component mounts with a different value. So to solve this problem, instead of doing this in the constructor, we can do it in componentDidMount. So let's do an action here in the store and call this action something like startClock. And this is going to basically do exactly that. We format that, and we'll just call this startClock action from the App componentDidMount. So on componentDidMount, after we subscribe to the store, we're going to do this.prop.store.startClock. So let's go ahead and test that now. So now my App is ticking and I don't have the problem of the check sum here. Cool! So the reason I started a timeStamp timer here is that in the next module, we're going to talk about the performance a little bit. And we're going to see how putting things on the state is going to affect the performance of the React application.
Subscribing to State from Child Components
This Timestamp component is currently a simple presentational component; in fact, we don't need it to be a class component here at all, we can simply use a function component. One can argue, though, that this timestamp component should be a complete stateful one that manages its own state and tick the timer as well. In which case, we don't need the global state. However, I'm going to assume that this timestamp is needed elsewhere in the application and leave it as part of the global state. But instead of having the Timestamp component receive the value of the timestamp as a prop, maybe we can have the Timestamp component itself read that value directly from the state. We are managing the state externally, so having child component read that state directly becomes an option. Please note that this is probably not the best option for this particular case, but the point here is to demonstrate that option, and in the next module we'll take a quick look at the performance of this application. So we can simply provide the global context store to this Timestamp component by using the storeProvider function. And to use that function, we just wrap the timestamp component with a storeProvider call. And remember that we need an extra props function. The extra props function actually is not optional, although we can easily make it optional here by checking for the value or provide the default argument. However I'm just going to leave it required for now. So we're going to need an extra props, I'm going to define this function here, and it takes in the store and the original props, in case I need those, and it returns an object of props. So let's think about that. I don't want to pass the timestamp directly here. I want to read the timestamp from the state. However, instead of reading it directly from the state like that, we can make it into an extra prop in here, so call this timestamp and read it from store.getState function dot timestamp, right? We have that option. We have access to the store here in the extra props. So this should work as expected. We don't need access to the original props, because actually I'm going to kill the original props, so in the timestamp here, we're no longer passing an original prop to the timestamp component. We are just rendering it and the timestamp component gets access to the store through the storeProvider and then it Maps an extra prop that is being read from the store state. And this will actually work. The Timestamp is still ticking. And we can validate that, we have a timestamp container, and we have a timestamp that takes the timestamp value as a prop. Now why exactly did this work? The timestamp component doesn't have a local state, it just gets property. Even the contained component doesn't have a local state. So this timestamp is actually working right now, because since the global state is changing, the App component is rendering, and the App component is rendering all the children components, including the timestamp container and the timestamp. Although if you think about it, the props and state of the timestamp container did not really change. So we might want to optimize our timestamp container, which is a valid case here. So I'm going to make it a pure component, which means if the props and state of the component didn't really change, then don't re-render. And if we do that, this timeStamp is going to stop ticking. So the question is why? Why did it stop ticking, when I changed the timestamp container to a pure one, although the timestamp value on the global State is still changing? We are reading that value directly from the timestamp component through the storeProvider. We're actually getting the initial value; however, the timestamp component is not ticking. So pause the video here and think about that. Why? The timestamp is a presentational component. It just gets properties, so it doesn't have any state, and now the container component is a pure component, so it's not going to re-render unless it has a reason to, which means it has different props or it has different state. So although the global state is changing, this pure component doesn't really care about that. If we want to make the timestamp component a truly connected component, which means a component dependent on the global state, we basically have to fake a state change in the container component every time the store is changed. So we need to subscribe to the store. So we can actually do the exact same thing that we did in the App component. So I'm going to copy these lines and put them in the storeProvider in here, paste the exact same code with a few differences. We don't need to start the clock here, we don't need to do setState in here, we'll talk about that in a little bit. We need to read the store from context instead of from props, because this is the higher-order component that accesses the store directly from context. So we subscribe to the store, and every time the store is going to execute on store change. When the store changes, I don't really need to set the state here at all. I actually don't need to manage State on this component. All I need to do is give this component a signal that it needs to re-render, because the timestamp component is reading something from the store, which means I need to re-render this component to cause the timestamp component to re-render as well. So we can actually simply just use a force update call. So every time the state of the store changes, just force update this component, because we know that a contained component might read the state out of the store and we need that contained component to re-render. So we can test that. And now the timestamp is kicking again, because of that force update call. So the timestamp container is a pure component; however, it's being forced update every time the state of the store is changed, and this will cause the timestamp component to re-render. Let me say this one more time. This is probably not the best option for this particular case; however, we did that just to demonstrate the option that since the state is managed externally to the React application, children component can subscribe to that state as well. We don't have to pass the state from the App component. So if we have a component that is five or six levels deep, instead of passing the state through the tree, we can subscribe to it directly from the child component and we can actually do that through the same storeProvider function. So now that we have a change state event every second, we want to analyze what's going on the React application, what is the React application really rendering, what is the React application taking to the DOM? And we'll do that in the next module.
A Bit of Refactoring
We started this module by upgrading the application package dependencies, and we used the upgrade-interactive yarn command to do that. I like this command, because it gives me a clear list of what will be upgraded, and I get to choose what to upgrade if I want to. We then started working with the state of the application. We first worked with React's built-in setState method, and we used that to manage a controlled SearchBar component and to place a searchTerm on the App top-level state, which the App component used to filter the displayed list of articles. We then moved the state of the app to an external entity, the store object, and we connected the App component to that state through a subscribe method. We also saw how to unsubscribe as well, and we implemented a simple notify all subscribers method that needed to be called on every store state change. Since we're managing the store externally, children component now have the option to subscribe to that state directly instead of relying on props. We saw an example of that with a system timer that manages a timestamp value. We've placed that on the top-level state that is managed by the store object, and we first passed that value to a Timestamp component as a prop, and then saw how to use the storeProvider function to also make a component connected to the store's state. In the next module, we'll analyze the performance of this simple application and see what options we have to optimize it.
Understanding shouldComponentUpdate and componentWillUpdate
In this module, we're going to talk about performance optimization and what tools we can use to help us measure things to be optimized. The advice here is, if you want to optimized something, you should measure it first and measure it after the optimization, because otherwise you don't really know if your optimization actually made things better. In a React application, most of the optimization concerns happen during the update operation of a component. The component lifecycle methods help us identify any areas in the code that could use some optimization. So let's make sure we understand those first. There are 5 lifecycle methods that apply to an update process in a React component. componentWillReceiveProps, which has an argument of those nextProps that are received. Every time the parent component re-renders a child component, the componentWillReceiveProps is invoked with the new passed in props, even if those props are identical to the current props. So a call to componentWillReceiveProps does not really mean that the component is going to rerender. Also, if the component sets its state internally, this would generally not trigger the componentWillReceiveProps lifecycle method. So this method is actually not super useful for performance analysis. shouldComponentUpdate, has 2 arguments of the nextProps and the nextState for a current update operation. This lifecycle method is very important, because we can actually use it to cancel an update process. Returning false from this lifecycle method tells React to not re-render the component at all. This is very useful for pure components. If the component is being passed the exact props and state, and we know it's pure, which means its output will be exactly the same, we can use an if statement in a shouldComponentUpdate lifecycle method to compare current and next props and state and return false if they're the same. That's exactly what the React Pure Component class does. However in some cases, we might need different logic to short-circuit the React re-rendering process based on other conditions. We'll see an example of that in this clip. The other lifecycle method that's helpful when analyzing why a component has re-rendered is componentWillUpdate, which is reported immediately before the rendering step. If we expect a component to not re-render, this lifecycle method should not be invoked. Also if this lifecycle method is being invoked while the rendered output is exactly the same, we basically have a wasteful render. Let's see an example of that. Let's work with the SearchBar component. The SearchBar component is a regular component, so I'm going to go ahead and define shouldComponentUpdate, and I'll just return true here, and I'll also define componentWillUpdate. And in here, let's just have a log statement updating SearchBar. Very simple. Let's test that. So every second we are updating SearchBar. However, we don't really need to update SearchBar at all. SearchBar doesn't need to be re-rendered every second. It's being re-rendered because the global State is changing and the App component is re-rendering, and that makes it re-render all the children component, including SearchBar. So in shouldComponentUpdate, if we just return false in here instead of true, and retest now. The SearchBar component is not being re-rendered at all. Right? Because we're short-circuiting the update process for that SearchBar component. However, that means we can't also type in the SearchBar component because it's not going to re-render at all. So to fix the problem without breaking the SearchBar component, we would compare nextProps with currentProps and nextState with currentState and return false, if they're exactly the same. That's actually what React pure component does. So we can just use pure component here. So let's test that. With a pure component, the SearchBar is not re-rendering, but we can type in it. And when we type it re-renders, right? Because we typed six letters, it re-rendered six times, but that's about it. It doesn't re-render every second. So here's my advice, always use pure component, unless you have a reason not to. Okay, so let me clear that up. And now let's target another component. Let's target the Timestamp component. Same thing, we will do a shouldComponentUpdate in here and just return true and the componentWillUpdate lifecycle method and console.log updating timestamp. Let's take a look at that. And the Timestamp component is getting updated every second, which is actually a valid case. Right? Because we are updating the timestamp every second. So in this particular case, React pure component doesn't add any value really, because we are updating the component every second. However, if this component is being updated for different reasons, other than the every second update, then a pure component would help. But we're going to need to dig deeper to know if the component is being updated for different reasons. However, let's assume that this Timestamp component is needed to render only the time part, not the date part, and actually not include the seconds, just hours and minutes. In that particular case, I don't need the Timestamp component to re-render every second, I just need it to render every minute. So let's test that. We can simply make the Timestamp component renders just the hours and minutes using this expression, which I totally got out of Stack Overflow. So this casting method takes a second option here, and we can specify what to display in there. So we have hour and minute only now. And if we re-render the Timestamp component now, we see just hours and minutes. But the Timestamp component is still ticking every second. So actually 59 of those update operations are going to be wasteful. We don't need the component to re-render every second, we just need it to re-render every minute. Here's the thing, even if I converted this component to a pure component, that's not going to help me. I'm gonna comment out shouldComponentUpdate and leave it just to pure component and see if that's going to help me. Will it? It will not! It's still ticking every second. Why? Because actually our nextProp as read from store is going to be different, we are receiving a different timestamp. However, we're only displaying just the hours and minutes of that timestamp. So we have two solutions here, either we'll make the container component pass just the hours and minutes and just display that, which is actually really simple to do. We just move this method into here. And let's test that. So now it's not re-rendering every second, because the prop itself is being passed differently and the pure component is doing its thing here and saying I don't need to re-render. But let's assume this wasn't an option. I need the timestamp value to be passed to the Timestamp component and I need the render method to cast that value into just the hour and minute string. What can we do to make the component not re-render every second? We can use a custom shouldComponentUpdate. We can do something like the currentTimeDisplay, which is what we're rendering. And the nextTimeDisplay is the exact same statement, but instead of this.props nextProps, just like that. And we can return currentTimeDisplay does not equal nextTimeDisplay. So if what I'm displaying next is different than what I'm displaying currently, go ahead and re-render; otherwise, don't re-render. So we can test that. And now my time component rendered the hours and minute, and it's not being re-rendered every second. And that happens thanks to the custom condition that we just added in shouldComponentUpdate. And when the minute ticks, we'll go ahead and actually update the timestamp, because the next timestamp display is different than the current timestamp display. So that's a valid case for some custom logic inside your shouldComponentUpdate, unless you don't want the actual timestamp value in the Timestamp component and you can just pass it what it needs to re-render. Of course in here, we are repeating this logic, so we should probably extract it into a function. So I'm going to go ahead and do that off-camera. So we now have a time display function that returns the string that we are interested in, and we are using this time display function in the render method. And in shouldComponentUpdate we are comparing the time display for the current timestamp with the time display for the next timestamp. And if they're the same, we don't need to update. So let's test one more time and make sure the Timestamp component is rendering and it gets updated when it needs to, but not all the time. So we didn't use the nextState here, we can remove that. And also we can remove the will component update. So I'll leave this in the code as an example of an actual use case for shouldComponentUpdate with some custom logic. But again, this is probably not the best way to do that, this is just an example.
Profiling Components in Chrome Using the react_perf Flag
We can use the Chrome performance tab to record and analyze the performance of an application as it's running. This is very helpful when analyzing why React components render and re-render. The report here shows very useful metrics on which we can zoom and analyze, but it gets better. React actually support a very useful flag that will give us even more details related to the React application. All we have to do is add a react_perf query string value here and record the performance of any interaction we want with the application. So let's do that and see what we get. Reload the app with react_perf while the Chrome performance tab is active. And here's where you're going to get differently. You're going to get this user timing section, and in this user timing section, let's go ahead and zoom on that, you'll see the actual React components here, and this is a visualization of every component mount update, unmount operations. So here's the App component, which took 24.8 milliseconds to render. And during that time we rendered the Timestamp, we rendered the SearchBar, and we rendered an ArticleList, and the ArticleList rendered many other components in here. So you can zoom in to see what is going on in here. You'll see how, for example, in the Timestamp component, this is the time that timestamp container took, and this is the constructor for the timestamp container, this the render for the timestamp container, which rendered the timestamp. So you'll see a lot of detail for every operation in the component lifecycle. So this is helpful to take a general look and see if something is weird. If one component is actually taking longer than it should, or if an unexpected operation is happening in the wrong time or place. The numbers that you see here are all relative, because this is running in development mode. So actually in production, things are going to run faster, but this is still a useful indicator of what's going on in development. You can use this visualization to see if an update is happening by mistake. And you see the update tree here, so how deep the tree is being updated and how often the updates are occurring are all things that you can quickly visualize by just looking at these performance metrics. So this should actually also work in IE Edge, I think, but I haven't really tested that. But eventually this should work in all browsers, because React is using the standard user timing API to integrate these metrics.
Perf Addons: Avoiding Wasteful Rerenders with PureComponent
If you're interested in more details about what is going on in the React application, React has a performance tools addon that is really helpful, react-addons-perf. So let's go ahead and bring this to our application, yarn add -- dev react-perf-addons. And we'll go ahead and import this performance addons in our code. I am going to import it in the App component in here. So I'm only adding the react addons perf as a development dependency, because we're just going to use it in development mode. And we can use this perf addons in many ways, but the simplest really would be to just place it on the window. So window.Perf = Perf and then interact with this perf tool within the chrome console. But I think that's actually going to break our server in here, because we are doing server render and window is not defined on server render. So actually if you want to use window in a server rendered component, you have to put it behind an if statement. And that if statement, basically is if typeof window does not equal undefined, then you can use this statement, otherwise you will do nothing. I think this will make the app happy. And now if we re-render the application, we would have the performance object on the window. So this is actually the full api of the performance object. We can do a start and a stop, and we can print DOM exclusive, inclusive, operations and wasted. So let's go ahead and test those. We do Perf.start, that's a function, this would start the measurements. And our application is ticking every second really, and its re-rendering the whole tree every second, so I know that we have some wasteful operation going on. So let's go ahead and stop that. Just do stop, and then take a look at the wasteful operation, with Perf.printWasted, just like that. And you would see how we have so many wasted operation in this application. So ideally this printWasted function should output nothing, because otherwise you have a lot of renders that are totally unnecessary. So we can solve this problem now that we can measure it. However, before we solve this problem, we should see a consistent measurement. We should have a way of always seeing consistent numbers here. So to do, that I am going to invoke Perf.start and Perf.stop in particular points in the application. So how about in componentDidMount we do a Perf start. Now sometimes when you do that directly you get this error that the mark did not exist, and this is a specific issue with the Perf component. There are some restrictions on using it, but one thing we can do is to put the perf start code in a set immediate call to be invoked in the next tick of the event loop. So set immediate function and then perf start inside that function and that would be okay. And I'll go ahead and set timeout. And do that after exactly five seconds and perf stop in here. So after five seconds, we'll stop the performance and we'll go ahead and Perf.printWasted. So hopefully doing this would give me consistent numbers of the wasted operations. Let's go ahead and test. So after 5 seconds I should see the wasted table, and I see 25 article list components were rendered wastefully, Article container as well. The App component itself was wastefully re-rendered five times and so is the article timestamp and search component. Okay so let's retest this and make sure we're getting the exact same numbers after five seconds, and we are. So this is consistent measures. Now I know if I start doing some changes, if these numbers go down or go up, I know that my changes are causing that, and not the fact that we are measuring different durations or different cases in the App component. We're always getting 25 in article lists, 25 in article container and so on. So there are many reasons why a React component gets wastefully re-rendered, and we can avoid most of these reasons by using pure components. So let's take a look at these components. So the container components are all wastefully re-rendering, because we're basically force updating those every time the state of the store changes, which is every second. So that makes sense, I'll come back to those later. But let's see why this article list component is being re-rendered, that does not make any sense. Right? Let's take a look at article list, and the article list here is a function component. And here's the thing, the article list component does not really need to re-render at all, because it doesn't change. What changes is the global time, so the article list component and all the articles really don't need to re-render here. But the thing is, function components always re-render, because React doesn't really optimize function components. So if you're not using a higher-order component that optimizes the performance of a function component, then using a function component is actually a bad idea, because it will always re-render no matter what. Now we have two solutions here. One solution is to call the article list component directly, instead of calling it as a component, because it's a function. Right? So instead of doing that, I can call this function directly. I could do something like, ArticleList, call it with an object that pass in the articles, just like that. And that actually is going to work and make us avoid the unnecessary render in the article list component. So let me test that. You'll see the application is still rendering correctly, and the wasteful table doesn't have my article list container. So that's one way of voiding an unnecessary render in React application. However, by doing so we really lose some value of this component. If we take a look at the react dev tools at this point, we're not going to see the article list component, we're just going to see a div here. There's no article list component surrounding the article container. But it is better, in terms of performance. However, how can we keep the article list component as an actual component in our tree, but not wastefully re-rendering its content when it doesn't need to? The answer is, don't use a function component, use a pure component instead. So I'm going to take the exact same return and instead of using an article list function component, I'm going to use a React.PureComponent ArticleList, and return exactly what we had before. And instead of props.articles, it's now this.props.articles. So the exact same thing, but instead of a function component, we're now using a pure component. And here's the thing, that will get rid of the wasteful re-render in the article list component. Let's test. So the application is still re-rendering through a component, and I don't have the article list component reported as a wasteful render, thanks to the pure component. Because if your props and state are exactly the same, we don't need to re-render. This is an optimization that we can do. So I've probably said this a few times already, but here is the advice, always use pure component, unless you have a reason not to. And the other advice here, avoid function components, unless you are using higher-order components that optimize the performance of function components. For example, if you're using react-redux, then react-redux is going to optimize the performance of any wrapped component. So using function components in that case is okay. But if you're not using react-redux, you're much better off using pure components than using function components. The React team is working on optimizing function components, but until they do, avoid them. So we still have five instances of wasteful renders here. Let's see if pure components is going to solve that. I'm going to go ahead and change the Article component into a pure component, instead of a function component and see if that's going to help me. And let's take a look. So I previously had a twenty five wasteful re-render in the Article component, and I think those are going to go away with just using pure components, and they did. Let's take a look at the other components. So we still have four instances of wasteful re-render, three of them are actually for the Container components, which are all provided through the storeProvider. And there's also the App component itself, which is being wastefully re-rendered five times. So sometimes using a pure component is not going to be enough. For example, if we changed the App component into a pure component, that's actually not going to help us. And I'll go ahead and test that. Refresh and you'll see that the App component is still being wastefully re-rendered five times. So using a pure component is recommended, but just know that sometimes it's not enough. You have to dig deeper to know why the component is being re-rendered.
Making Store-connected Components Subscribe to Partial State
In the previous clip, we changed the App component into a pure component, but that did not help us, because the App component is still wastefully re-rendering five times in our measurement period. So to optimize the performance of the App component, we need to carefully analyze what is going on. And that means looking at render method of the App component and what render method that is using. And by carefully looking at the render method of the App component, we know that it's using the articles object and also the search term from the state. But the App component initializes its state as the full state of the store. And then for every change in the store, it locally sets the complete state of the store as its own state. But here's the thing, the App component doesn't really need the full stored state. It only needs the articles and the searchTerm out of the state. So the fact that we have more properties on the state that changes, makes the App component re-render wastefully. Now there are a few solutions to this problem. The simplest solution is to customize the shouldComponentUpdate operation of the App component. And basically, we can have a condition here, to return true, only if the nextState.articles does not equal the current state.articles or when the nextState.searchTerm does not equal the current state.searchTerm. And that actually should solve our problem. Let's test. Re-render, and the App is working fine. The search is working and we don't have the App component as a wasteful render. The timestamp actually just ticked, so everything is working. But we don't have the App component as a wasteful render. And all of what we needed to do is to customize the shouldComponentUpdate and only actually re-render if we have a reason to. However, while this solution works, it's not really the best solution, because this means that there is a dependency between the render component and the shouldComponentUpdate. So every time we want to use a new property on the state inside the render function, that means we need to change the shouldComponentUpdate logic to include that thing, so we can actually do better than that. There's another solution to this problem. Instead of subscribing to the whole state, we can just subscribe to a portion of the state. So we can, for example, have a function in here. Let's name it appState, and this function reads the store state. So instead of reading the whole state in here, we can just read the articles and the searchTerm out of the store state. So destructure articles and searchTerm out of the store state and then return those, articles and searchTerm, just like that, because this is the exact state that we want out of the store. And now, instead of reading the state of the store directly, we can always read this.appState in here and also in here as well. And if we do that, the state of the App component only changes when either the articles or the searchTerm changes. So let's go ahead and test that. The app is rendering. I still search, things are working. We'll verify that the time is ticking and I do not have the App component as a wasteful render. So the application is working exactly the same, but now the App component only subscribes to a partial state of the store. And also the timestamp is still ticking. Now you might ask, how is it that the timestamp is still ticking when the App component is not really aware of the timestamp state? And the reason is, the timestamp component reads the timestamp state out of the store directly, it doesn't need the App component to read that. So we made the App component independent of that timestamp change, and now App component only re-renders when either the articles object or the searchTerm changes. And that's a much better way. In fact, we should always do that, we should always make a connected component subscribe to the part of the state that it's interested in, not the whole state. Because subscribing to the whole state will cause us to do wasteful re-renders. This also applies to the remaining cases of the wasteful re-renders, which are all the container component. Because the container component right now just force update themselves when the state of the store changes, but really they don't need to. They only need to force update, if the state of the component that they contained is changing. And we can actually do this optimization really easily. So let's take a look at the contained components. The Article component is contained. It depends on the author, so it doesn't really depend on the state at all. The searchBar component doesn't depend on any extra states, as well. The timestamp component does depend on an extra state. So the timestamp component needs to force update when the timestamp property on the state changes, but nothing else, only when the timestamp property of that state changes. So the extra props function here is key. If we're returning from extra props, a property that depends on the store states, then we force update the component if that property changes on the state. So we can generically do that in the storeProvider function. Let's try to do that. Instead of force update, let's think about doing a setState call, but only for the part of the state that is actually relevant. So let's call this part, this.usedState. And I'll make that into a function. So this usedState function would be only the properties from the state that are being used by the wrapped component. And we can compute these properties from the extra props function. So we have two cases here. Sometime we return an extra prop that uses the state. And sometime we return an extra prop that doesn't really use the state. To simplify the logic of what we need to do next, let's just assume that everything in the extra props is a usedSate. So the usedState is actually the extra props call itself. So I'm going to create a usedState function and just return the extra props function, invoked with the context store and this.props. And I'll go ahead and use it here as well, so this.usedState. And now the container component only sets the state that's being used by the wrapped component. And I think that is going to get rid of some of these wasteful re-renders. Let's test. So the app is rendered correctly, but I still the article container, the searchBar container and the timestamp container. So let's go ahead and dig deeper. I'm going to kill this force update. And to figure out why these container component are still re-rendering, we need to do an inspection inside the componentWillUpdate. And in here, we can just simply console log this.state and the nextState, just to see what's going on in here. Let's go ahead and test that. So we have a few cases here. Let's first focus on the searchBar container, which is being wastefully re-rendered once and here is the call here. So it started with a null state and the nextState had an empty object. So we can easily fix that. So this is actually happening because I don't initialize the state. So let's go ahead and initialize the state, which is exactly the same, state = this.usedState. That actually should fix the searchBar component, because now it will always be an object. So let's test that. However, I'm getting this.usedState is not a function, and that's actually because we need to put this.usedState before this operation. Let's make sure things are working now. And they are, and now let's take a look at the wasteful renders. The wasteful renders is now only the timestamp component. So by making the higher order wrapped component subscribes to only the part of the state that is being used, we fixed the wasteful renders of both the searchBar component and the articles component. And now the only wasteful renders is happening in the timestamp component. So why is the timestamp component being wastefully re-rendered every second? Well, because we have the logic of time display in here, inside the timestamp component itself. So the timestamp container is still ticking every second and it's still changing the timestamp value. And the display portion, the timestamp component, is only re-rendering every minute. So we can fix this problem by moving this logic to the timestamp container component. So instead of using a shouldComponentUpdate here, and instead of rendering this.timeDisplay timestamp in here, we can do something like this.props.timestampDisplay and call the timeDisplay function in here, so this.timeDisplay is what we're interested in. However, I don't have access to the component instance inside the extra props. But here's the thing, I don't need access to the component instance, because this timeDisplay function doesn't really depend on the component instance, so I can actually make it into a static function. And instead of calling it with this.timeDisplay, I call it with Timestamp, the component itself, .timeDisplay. So let's test that. Now the application is re-rendering, but I don't see the timestamp display at all. So let's fix that. So the property here is timestampDisplay. All right, let's test. I see the timestamp and it's not being wastefully re-rendered. In fact, the wasted table operation is empty. You see that? You don't have any more wasteful operations. And the timestamp component is still working; every minute the time is going to change and the timestampDisplay is going to change and the timestamp container is going to re-render correctly. When it does, it's not really being wastefully re-rendered, because it's re-rendering different content to the DOM. So now we can remove this componentWillUpdate lifecycle method, because we just used it to figure out why the component is being re-rendered. So let's do one final test. Make sure the search is working, and it is. Make sure the timestamp component is re-rendering, and it is. So at this point if you don't want to do any more performance optimization analysis, we can practically remove the Perf code. So both the setImmediate and the setTimeout calls can go away in here. So this analysis of why the component updated, is very important. In fact, there's a package that you can actually use to see why components are updating unnecessarily. And it gives you exactly the values before and after and it tells you if an unnecessary re-render is avoidable. So if you don't want to do what we did manually, you can also use that package to give you some clues of why some component are re-rendering unnecessarily.
Immutable Data Structures
Sometime when you use a pure component optimization, you'll run into unexpected problems. And this happens particularly when your state has mutable structures, like objects and arrays, and if you're actually mutating these structures. So let me demonstrate this problem with an example. Let's go to the state api class, where we manage the store. And we are managing the list of articles here as an object, which is a mutable data structure. So I'm going to do an example of mutating this structure. So let's assume that after one second, we received another article from the api. So to simulate that after one second, so I'll do a setTimeout operation that gets invoked after one second. And in here, we're going to have a fake article, and we'll append this fake article to the articles object that we have on the state. So I'll copy this fake article from the rawData, so we'll copy rawData.articles first, and we'll just give it a fake id. So now I have my data articles as an object, and if we want to add this fake article, one option would be to just do this.data.articles for this fakeArticle id = the fakeArticle. And I also need to notify the subscribers, right? So this.notifySubscribers call in here. And what we're doing here is we're basically mutating the state. And if we're mutating the state, the pure component optimization that we did in the App component is actually going to give us a problem, because as a pure component sees it, the articles object reference did not really change. So if we test what we just did, it's not going to work. I will not see this new article, again, because we are using a pure component. In fact, if we remove the pure component optimization from both the App component and the article list component, then what we just did should work. Let's test. So render the first list, and after one second the fake article should show up on the list. So the fact that we mutated our state is now preventing us from using pure component, which is bad. So I'm going to put back the pure components and go back to the same problem. Now we are changing the state of this component, but we are not re-rendering, because we are using pure component optimization. So how can we do the exact same operation without mutating the state? We can use a copy operation. So something like this.data equal, start by copying the current data, then change the articles object. And start by copying the current articles object from the data, and then add the new article. So in here, that would be fakeArticle.id is the fakeArticle. So what we're doing here is practically equivalent to the commented out line, but without mutating the state. We are copying the current state and then modifying a copy of the current state, which means for the pure component, the previous object and the new object are going to be different, and things should work, even though we have pure component. Let's test. Re-render, we get the list of articles first and after one second, a new article shows up. And again, we're still using pure components here and here. However, now we are not mutating our data structures. So here's the advice, always use immutable data structures, never mutate your data structures directly, because that's going to have performance implications on your application, eventually. However, when you start copying object to avoid mutability, things might start to be harder than they should. Right here we needed a few lines of code to replace a single line of code. And we have to do these manual copy operations, which actually cost something, in terms of the resources available in the browser. So although we removed some complexities by not mutating the data directly, we added new complexities of needing to copy data around and use memory and cpu to do so. So the best of both worlds is to use some kind of immutability helper. Now you have options here. And the first option is the immutability helper package, which is a very simple helper that allows us to update an object without mutating it. So it actually returns a new copy of the object, and it uses syntax similar to MongoDB here as dollar sign set, dollar sign push. So this is actually the minimum you should use in a React application, if you're managing your own state and you want to utilize the pure component optimization. If you want a more advanced option, you can use the immutable js library, which has a lot more features. Like for example, you can work with lists and maps. And not only you can update these data structures in an immutable way, but you can also do operations like merge and deep merge and deep update. So it's a very rich library to work with immutable data structures. And the cool thing about it, is that it actually uses shared data to do these immutable operations in a very optimal way without wasting resources unnecessarily. But it does add complexities to the project. However, I think the complexities that it removes are much bigger than the complexities that it adds. So I've actually started using immutable js in all of my React projects, because I think the values it adds is simply great.
We talked about performance optimization in this module. We first talked about the update lifecycle methods that happen right before a component gets updated, and saw how two of these are very helpful for performance analysis and improvement. shouldComponentUpdate can be used to cancel an update process, and componentWillUpdate can be used to verify that an update is happening when it shouldn't. We talked about how React's PureComponent class optimizes the render process for pure components, but we also saw examples of how we can also use shouldComponentUpdate with custom logic. We looked at using Chrome's performance tab to visualize what's going on with the application and saw how React has a special react_perf flag that provides a user timing section in the recorded performance which visualizes the mount/unmount/update operations for every component in the app. React has another very handy tool to look at the performance of components, especially when they get updated, and that is the Perf addon. This tool allows us to start and stop measuring certain things about a React application, and then it will report those things out nicely. One helpful thing that it measures is the wasted renders, which is when a component is being re-rendered, but its output remained exactly the same. Seeing those measurements allow you to know where in the application there is room for a good refactoring that would avoid any unnecessary re-rendering. We also learn a trick of how to subscribe to only the part of the state that is relevant to a component, because otherwise you'll have changes that drive unnecessary re-renders. This is only valid if you have an external state, but the same idea applies to props as well. A component should only receives props that are significant to its outputted render. Finally, we saw how simply mutating the data prevent us from using some optimization, which is bad. Using immutable data structure allows for much easier optimizations in React and it's a very good strategy to adopt globally. In the next and final module, we'll go over some best practices for deploying React applications to production. This also falls into the performance optimization category, but it's not an optional one. Running a React application in production without optimizing its build is a bad idea, and I'll tell you why in this next module.
Production Deployment Best Practices
React’s Production Build
The one optimization in your project that you should definitely do is to use minified production builds for all dependencies and for your own application as well. Right now, we have a single bundle.js file that is about 3 MB, which is a big number. Even half a megabyte would be a big number when working with just text files. But it's not really just about the size and its related network cost, it's also about the performance of code after it's been downloaded, and that is especially true for React. In fact, this is so important, the React team made so many signals to make sure that you don't run a development build in production. React will give out warnings about that, and recently the dev tools introduced an icon with colors about that. This red background here means that you are using a development build for React. And if you go to a site that uses React in production, that icon should turn blue on black. So why is this so important for React? Well, because React has many helper tools in development that we can do without in production, including things like prop-types validations and the useful detailed warnings. These tools that are designed for development make the development build larger and slower. Building React for production basically strips these development tools out to make the build smaller and faster. Of course, developing a React application using a production build would be a bad idea as well, because, for example, instead of getting a helpful warning when something is used in wrong way, you would just get a number or something that's not helpful at all. Unfortunately, the process of deploying things to production in general is not an easy one. There are many configurations needed for various reasons, and it's important that we understand these configurations and their reasons. If you want to sync the code as of now, it's tagged in the repo as module-7-start.
Continuous Integration and Test Coverage
The very first thing that should be validated before initiating a deploying process is the green build. You have to make sure all tests are passing and your test coverage is decent. I've been keeping an eye on the couple of tests that we wrote for this project manually, but relying on a manual check like that in a project is not a good idea. You are going to forget. You should automate the tests check. There are two things you can do for that: first, if the whole test suite runs fast, you should run all the tests before each and every git push you do. To automate that, you can use git hooks, which allow you to write custom code to be invoked before and after certain git operations, like commit or push. But practically, the test suite will start taking longer and longer, and running it per git push is going to start frustrating you. This is when you should go async. Use a continuous integration service and get alerted when the build breaks. An excellent testing integration that plays well with GitHub is Travis. It automates the process for you on every push. Failing tests should be treated as a top priority in any project. Ok, tests are passing and life is good, but how much of this project is actually being tested? This is a very hard to answer question, but there's something that we get out of the box with Jest that can help us make an estimate. It's the coverage report. Now we only did a few example tests for this project, so I bet our test coverage is not good at all. Let's take a look at that. All we need to do is to add a dash dash coverage arguments to the jest command. I'm actually going to introduce a new script, let's call it verify tests, and I'm going to call this with jest, I don't need the --watch for this one, but we'll do --coverage. Okay, so let's run this one, yarn verify tests, and it's running just with --coverage, and this is the report. The only component that was tested is article list, so we have good coverage there. We have a little bit of coverage in the other files, but it's not enough. For example, only 27% of the storeProvider function is tested, and jest actually gives you the lines that are not tested, so this is a good indicator of where you should be writing more tests. So ideally this report should be all green, and your coverage is 100%. But even if your coverage is actually a 100%, it doesn't really mean that everything is tested properly. It just means that all the lines and functions were executed during the testing run, but sometimes you have to execute functions and lines in many ways and with different inputs to test all the cases. But this coverage report is your first step. Get this degree and maintain 100% coverage all the time, and then start thinking about the more cases that you need to test certain things. There are also other options where you can actually fail the test if the coverage is not good. If, for example, the coverage fails below a certain point, you want to just give a signal to everybody that the test is failing, because the test coverage dropped. Because, again, unless you automate these things, you're going to forget to check things like coverage. Running this coverage command is going to introduce a new coverage directory under this project, so this is something that we should probably git ignore. So in here I'm going to ignore coverage, make sure it doesn't show up in the Git Status, and now we can commit.
The following step is optional, but right before you put the application in front of people to test it, it might be a good idea to see if there are any non-major upgrades that you should try to perform first. Non-major upgrades should not break things, theoretically, but might start giving you some deprecation warnings, and now is a good time to decide on those if they start to happen. This step should only be carried out in a green state, and preferably, if you have a human QA process, you do this upgrade right before you hand the project to the QA team. Let's take a look at the upgrades available for us now. We do yarn upgrade-interactive. And it looks like we have a few. Most of the NPM packages follow semantic versioning, with three numbers: Major, minor, and patch. For example, the React update here is just a patch, so it should be safe to do. However, the Webpack upgrade is a major one, so that might not be backward compatible. So if we choose to upgrade Webpack here, we want to make sure that things did not break. Webpack is probably okay to upgrade here, because it's in our dev flow, so verifying its task is easy. I'm going to go ahead and upgrade everything. So the first thing to check after the upgrade is the tests. So we'll run yarn jest, and our impressive test suite is still green. That's good. Let's restart things. So first, let me reload the pm2 process. Take a look at the logs, and pm2 seems to be okay here. Let's restart Webpack. And we're now running on Webpack 3, and it's not giving out any errors. So let me verify the application itself, make sure nothing broke. And things seem to be working, so I'd say this seems to be a safe upgrade to do. So ship it.
Separating Vendor Files
The bundle file for this application currently includes all the front-end dependencies like React, axios, and the lodash functions we used, and we need to deploy that to production. After that, we're going to make changes to our application and deploy a new version of this bundle.js file. However, if you think about it, when we deploy version 2, we're likely going to change just our application, not the vendor dependencies like React. When we deploy a new release of this bundle.js file, we would be invalidating the whole cached file in all browsers that used the application. This is wasting some good cache. We do not need to invalidate the whole thing, we only need to invalidate the part of bundle.js that we actually changed. This is why it's currently a good idea to split this bundle.js file into two files, one that represents our own application, and another to represent all the vendor files that would not be changed as frequently as our application. Webpack can help us with that. We need to do two configuration changes to make that happen. First, instead of this array in the entry file, we can do an object here. This object will have two properties; one property for the vendor files and another property for our own app. So we can take what we had before here and make that our own app, and then introduce another array for all the vendor files. Actually, the Babel polyfill is also a vendor file, so I'm going to remove it from here, keep just the DOM renderer in our app, and put the Babel polyfill file in here. And also we need to add react react-dom, we also used prop-types and axios, and we also used a few lodash functions. So we have lodash.debounce and we also have lodash.pickby. All of these packages are vendor files that would not be changing as frequently as our own application. We also need to include this commons chunk plugin for Webpack to do the actual separation. This receives a number of options. I'm going to copy an example here, we're doing this explicit vendor syntax. So we did the vendor, and now we need to include this CommonsChunkPlugin. This is something that we need to include as a plugin, so we do plugins is an array of plugins and we include the CommonsChunkPlugin. And we need to require Webpack, since we haven't done that before. Now before we test, since now we have two entry points, the output should be two files not just one bundle.js file. With Webpack we can use this syntax, we put name in square brackets like that, and that means for every entry point generate an output file that matches the entry point property in here. So we'll have vendor.js and we'll have App.js. So I think we can go ahead and test. Just restart Webpack. And now you should see two bundled files, App.js, which is our own application, and vendor.js, which is everything else. Now we also need to change the views ejs file to include both of them. So we need vendor.js and we also need App.js. This way when it's time to release a new version of our application, we only change App.js. Vendor.js can stay cached in all the browsers that previously used this application. However, when it's time to invalidate the cached version of App.js in all the browsers, we need to do something different here; otherwise, the browsers might not actually fetch the new release. So it's a good idea to have something like a version here, so version 1. And also this is something that you want to do for vendor.js as well. So when we release version 2 of our application, we would change that into two. And when we upgrade the dependencies of our application and release a new vendor.js file, we would change that version separately. This versioning is also something that you should automate as well. And to do that, one option would be to generate this index.ejs file every time we release a new App.js file and make that part of the production build for this application. Now that we have two bundled files, we need to ignore these separately. So, public vendor.js and app.js, because both of these are generated content that should not be in source control.
Minifying Bundled Files
The next task is to minify these bundled files. Right now we have these sizes and we can use Webpack to minify them. So let me create a new script for that. I'm going to call it build-webpack. And basically we need to do webpack -p. So let me test that real quick. Yarn build-webpack. And you'll notice how the sizes for the files that we bundled went down significantly. The vendor.js file went from about 3 MB into just 260 KB, so that's one step that you should definitely do in production. Let's test our application now, and notice how the React dev tools icon is now blue on black, that means we're using a production build of React. And if you take a look at the network now, we are loading vendor.js and App.js with their minified versions here. So this makes the resources needed in production ready. However, we still need to do one more thing. We still need to build Node itself, because in development, we used babel-node and using babel-node in production is probably a bad idea.
Using Different Babel Configurations
Running Node.js in Production
One final optimization that you should do in production is to run multiple node instances per processor core. When we we just run a node command, it creates a process that uses a single CPU core. If you're running the command on a machine that has multiple CPU cores, you should start a different node process for each core. On this machine, I have four logical CPU cores, which means I need to run four different node processes. Node has a built-in module to help with that. The Cluster module. I cover details about using the Cluster module in the Pluralsight course about Advanced Node.js. The PM2 tool that we've using in this course wraps the Node.js cluster module and offers a much simpler syntax to take advantage of Node's multi core load balancing capabilities. All we need to do is use the -i argument with the number of instances we need to start. And we can use max to use all available CPU cores. We can also use the PM to reload command to do a zero downtime reload of all the running instances. So let's create a new script to run node in production. I'll copy the dev script in here, and let's call this script start-prod, and it's the exact same command, except I don't need to watch and I don't need the interpreter to be babel node, because we're running natively through node. We're also going to run this with the build directory. So instead of lib here, we're going to go with build. So consider the NODE_PATH to be build and then start build/server.js. And go ahead and use -i max to use all the CPU cores on this machine. Since we're using PM2 for production and development, we could also name the process. So let's do - - name and I'm going to name this process as appProd. And let's name the dev process as appDev. So now if I check the logs of all the running processes, I would know which process is actually running. Another thing that we should do for the node process is to run it with NODE_ENV=production, so if any script is using this NODE_ENV special environment variable, it will be set to production in that case. So we can test now. We can take a look at all the running PM2 processes with yarn PM2 status, and I see the server which was our development process before we named it, so we can delete all the processes now. So now we have a clean PM2 status. We can run our start prod script, so yarn start-prod. And you'll notice how PM2 started 4 processes for the appProd project. This is because on this machine I have four different CPU cores. And PM2 is also going to load balance between these 4 processes automatically. I don't even have to configure any ports or anything. It will do that internally using node.js cluster module. So we can test the application now and make sure everything is working, as expected. This application is now ready for production. We can push all the changes to a server, run yarn to install dependencies, and then build for webpack, build for node, and then yarn start -prod to start the server with production settings for PM2.
Summary and Course Wrap Up
Samer Buna is a polyglot coder with years of practical experience in designing, implementing, and testing software, including web and mobile applications development, API design, functional...
Released21 Jul 2017