I’m publishing this one on the heels of the previous post because tomorrow is Saturday and I might forget.

Now we’re getting somewhere! Header.js is currently the workhorse of this system. Keep in mind that this file is only running the header of the site; it has nothing to do with the running of the rest of the site.

Lines 1-3 are the same import statements we’ve seen, but there are more of them. Because we exported the HeaderUser and HeaderTitle components from their files, we are importing them here so we can use them as tags.

Lines 6-15 comprise what is called the constructor. When a class component is first called, the code in this block is run during instance construction. The code here runs once and only once when the tag is called, therefore it’s a good place to run setup stuff. Of special note is that this function takes an argument called props. Why didn’t the other two components have constructor defined? Well, they did! It was just automatic, defined and run from the base code that we were extending. In fact, if we were to have created a constructor method for those components without adding any code, the React linter would yell at us that we were making more work for ourselves than we needed to. So in this case, you can see props entering into the component: it’s an argument passed in from the caller, although to make things confusing, we won’t be passing any data into this component. The constructor needs props as an argument, but it can be empty.

Line 8, super(props) isn’t a special kind of props. Instead, it’s passing whatever variables we have received to whatever this component is extending. Technically, we’re not building on anything except React’s concept of a component, but this line is required for safety reasons.

Lines 9-12 are very important, as they are initializing state. State in React is powerful and lame at the same time. State is a way of tracking values throughout a component, but only within the component in which they are assigned. If we load data in one component and put it into a state object, they are only available within that component unless we specifically move them down to a child component via props, or up to a parent component via an event. State is also a driver of one-way binding. When the value of a key held in state is updated, it’s instantly updated wherever that key is used in that component. We’ll see how important that is in a bit.

Lines 13 and 14 register two functions that we’ll use when working with our API. We have to do this for those functions to be defined properly. There are a few places and ways we can define functions, and unlike most other languages that I know, where and how you define functions seems to matter on where and how you can use them. [1]

Lines 17-21 constitute a lifecycle function. There are a few lifecycle functions defined in the component base that we extend, like componentDidMount(), which we can override for our own functionality. Here, componentDidMount() runs whenever this component has been instantiated. Think of its purpose as insurance that everything went smoothly, and once we’re sure of that, we can run whatever code is in this block.

So what do lines 18- 20 actually do? They use javascript’s fetch function to call an API and deal with the results. In our test case, the API is a local JSON file called User that contains just a username and an access permission level for this application. We’ll receive this javascript object, and pass it to a function called onUserGet. [2]

Surprise! onUserGet is defined on line 23. Once we have the data, we are updating our state with the info. Notice that unlike almost every other language out there, we’re not using a direct property or key-based assignment of the state object. Instead, we use setState(). This is the only way we can update state over time; the original direct assignment syntax is only good in the constructor() method of the class component. This is followed on line 32 by a function that we can use to handle any errors that fetch might have generated, but we’re not wired up to use it in this example.

Starting at line 36, we return to familiar territory with render() and return, although we make a variable assignment of username from one of our state variables. The use of <React.fragment> on line 39 is…I’m not really sure what that is. The IDE threw an error when I tried to return two div tags side by side — which is normal in HTML — and the StackExchange answer was to put those tags around the whole thing.

Lines 44 and 45 use our HeaderTitle and HeaderUser tags to call those components and render the content that they returned. However, HeaderUser has a property username = {username}. Remember that content inside {} tells React to parse the contents as code and not as literals, so the internal username refers to the variable we set right outside the render() statement. And the property username that we are assigning to? Believe it or not, that is being assigned to the props collection that we saw referenced in the HeaderUser.js file. Here’s a refresher on that one:

HeaderUser.js

Line 10 refers to this.props.username, which it receives through the property username that we assign to the instance of HeaderUser that we instantiate in our output of Header.

For our last post, we’ll look at App.js, index.js and index.html.

On Arrow Notation

Before I leave this post, I wanted to do a quick shout out to arrow notation. In the discussion of fetch you see code like response=> response.json() and data=>this.onUserGet(data).

Arrow notation has a few forms depending on what kind of data is involved, but basically what we’re looking at is a shorthand for function. We could re-write the above examples this way:

const res = function(response) {
   return response.json();
}

const usrData = function(data) {
   this.onUserGet(data);
}

In fetch, we’d call these functions as res(response) and usrData(data) and we’d get basically the same result. Arrow notations allow us to define functions in-line, although they can be kind of confusing if you’ve never seen them before (and honestly, sometimes I still have trouble reading them).

[1] I don't have specifics on this, but VSCode yelled at me for putting functions in certain places, and also for putting them in certain places in certain formats. It might be that there's only one way to use functions within a component and that I am overcomplicating things, but I suspect that where and how you define them matters for accessibility.

[2] Fetch is an up-and-coming ECMAScript 6 function, and as such, isn’t universally available — I’m looking at you, IE, as usual. After I finished this post series, I went back and created a JS library that checks the browser agent and if it’s IE, use XMLHttpRequest. Otherwise, use fetch.

Sound off!

This site uses Akismet to reduce spam. Learn how your comment data is processed.