Skip to content

Latest commit

 

History

History
350 lines (294 loc) · 18.3 KB

File metadata and controls

350 lines (294 loc) · 18.3 KB

5.1 React-What is React

How we can build up complex functions by combining simple ones together?

composition= built from simple functions!

Example: getProfileLink() function with composition:

function getProfileLink (username) {
return 'https://github.com/' + username
}

getProfilePic function:

function getProfilePic (username) {
  return 'https://github.com/' + username + '.png?size=200'
}

COMPOSITION

  • To compose these simple functions, just combine them together into another function:
function getProfileData (username) {
  return {
    pic: getProfilePic(username),
    link: getProfileLink(username)
  }
}

Example: getProfileData()function without composition: (provide the data directly)

function getProfileData (username) {
  return {
    pic: 'https://github.com/' + username + '.png?size=200',
    link: 'https://github.com/' + username
  }
}

NOTE: This is accurate JavaScript code. But this isn't composition.

Potential issues with this version that isn't using composition. If the user's link to GitHub is needed somewhere else, then duplicate code would be needed. A good function should follow the "DOT" rule= Do One Thing

This function is doing a couple of different (however minor) things;

  • it's creating two different URLs,
  • storing them as properties on an object,
  • and then returning that object.

YET, In the composed version, each function just does one thing:

  • getProfileLink = builds a string of user's GitHub profile link
  • getProfilePic = builds a string the user's GitHub profile picture
  • getProfileData= returns a new object

React & Composition

React makes use of the power of composition, heavily! React builds up pieces of a UI using components. Let's take a look at some pseudo code for an example. Here are three different components:

<Page/>
<Article/>
<Sidebar/>

Now let's take these simple components, combine them together, and create a more complex component (aka, composition in action!):

<Page>
  <Article/>
  <Sidebar/>
</Page>

Now the Page component has the Article and Sidebar components inside. This is just like the earlier example where getProfileData had getProfileLink and getProfilePic inside it. NOTE: Composition plays a huge part in building React components.

Composition Recap

Composition occurs when simple functions are combined together to create more complex functions. Think of each function as a single building block that does one thing (DOT). When you combine these simple functions together to form a more complex function, this is composition.

Further Research

What is Declarative Code?

Imperative Code

A lot of JavaScript is imperative code:

expressing a command; commanding

When JavaScript code is written imperatively, we tell JavaScript exactly what to do and how to do it. Think of it as if we're giving JavaScript commands on exactly what steps it should take. For example, I give you the humble for loop:

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']
const excitedPeople = []

for (let i = 0; i < people.length; i++) {
  excitedPeople[i] = people[i] + '!'
}

If you've worked with JavaScript any length of time, then this should be pretty straightforward. We're looping through each item in the people array, adding an exclamation mark to their name, and storing the new string in the excitedPeople array.

This is imperative code: We command JavaScript what to do at every single step:

    1. set an initial value for the iterator - (let i = 0)
    1. tell the for loop when it needs to stop - (i < people.length)
    1. get the person at the current position and add an exclamation mark - (people[i] + '!')
    1. store the data in the ith position in the other array - (excitedPeople[i])
    1. increment the i variable by one - (i++)

Declarative Code

In contrast to imperative code, we've got declarative code. With declarative code, we don't code up all of the steps to get us to the end result. Instead, we declare what we want done, and JavaScript will take care of doing it. This explanation is a bit abstract, so let's look at an example. Let's take the imperative for loop code we were just looking at and refactor it to be more declarative.

With the imperative code we were performing all of the steps to get to the end result. What is the end result that we actually want, though? Well, our starting point was just an array of names:

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']

The end goal that we want is an array of the same names but where each name ends with an exclamation mark:

["Amanda!", "Geoff!", "Michael!", "Richard!", "Ryan!", "Tyler!"]

To get us from the starting point to the end, we'll just use JavaScript's .map() function to declare what we want done.

const excitedPeople = people.map(name => name + '!')

NOTE: with this code we haven't:

    1. created an iterator object
    1. told the code when it should stop running
    1. used the iterator to access a specific item in the people array
    1. stored each new string in the excitedPeople array INSTEAD: all of those steps are taken care of by JavaScript's .map() Array method.

💡 .map() and .filter() 💡

React Is Declarative

We'll get to writing React code very soon, but let's take another glimpse at it to show how it's declarative.

<button onClick={activateTeleporter}>Activate Teleporter</button>

It might seem odd, but this is valid React code and should be pretty easy to understand. Notice that there's just an onClick attribute on the button... we aren't using .addEventListener() to set up event handling with all of the steps involved to set it up. Instead, we're just declaring that we want the activateTeleporter function to run when the button is clicked.

Declarative Code Recap

  • Imperative code= instructs JavaScript on how it should perform each step.
  • With declarative code = we tell JavaScript what we want to be done, and let JavaScript take care of performing the steps.

Why REACT is declarative?

React is declarative because we write the code that we want, and React is in charge of taking our declared code and performing all of the JavaScript/DOM steps to get us to our desired result.

QUIZ QUESTION

Is the following code imperative or declarative?

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']
const longNames = people.filter(name => name.length > 6)
  • ANSWER: This is declarative. We didn't provide all of the steps that JavaScript should take to cycle through the list. Instead, we just told it to filter the list.

Resources

Data-Binding In Other Frameworks

Front-end frameworks like Angular and Ember make use of two-way data bindings. In two-way data binding, the data is kept in sync throughout the app no matter where it is updated. If a model changes the data, then the data updates in the view. Alternatively, if the user changes the data in the view, then the data is updated in the model. Two-way data binding sounds really powerful, but it can make the application harder to reason about and know where the data is actually being updated.

Resources

React's Data-flow

Data moves differently with React's unidirectional data flow. In React, the data flows from the parent to a child component. Data flows down from parent component to child component. Data updates are sent to the parent component where the parent performs the actual change.

reacts-data-flow

In the image above, we have two components:

  1. a parent component
  2. a child component

The data lives in the parent component and is passed down to the child component. Even though the data lives in the parent component, both the parent and the child components can use the data. However, if the data must be updated, then only the parent component should perform the update. If the child component needs to make a change to the data, then it would send the updated data to the parent component where the change will actually be made. Once the change is made in the parent component, the child component will be passed the data (that has just been updated!).

Now, this might seem like extra work, but having the data flow in one direction and having one place where the data is modified makes it much easier to understand how the application works.

QUIZ QUESTION

QUESTION 1 OF 2: A FlightPlanner component stores the information for booking a flight. It also contains DatePicker and DestinationPicker as child components. Here's what the code might look like:

<FlightPlanner>
  <DatePicker />
  <DestinationPicker />
</FlightPlanner>

If this were a React application, which component(s) should be in charge of making updates to the data? Check all that apply.

  • ANSWER: Since FlightPlanner is the parent component and stores the data, any changes to the data should be made by this component.

QUESTION 2 OF 2: Now let's say that the FlightPlanner component has two child components: LocationPicker and DatePicker. LocationPicker itself is a parent component that has two child components: OriginPicker and DestinationPicker. If the following sample code were a React application, which of the following components should be in charge of making updates to data? Check all that apply.

<FlightPlanner>

  <LocationPicker>
    <OriginPicker />
    <DestinationPicker />
  </LocationPicker>

  <DatePicker />

</FlightPlanner>
  • ANSWER: The component that stores the data should be the one that updates the data.

Data-flow In React Recap

In React, data flows in only one direction, from parent to child. If data is shared between sibling child components, then the data should be stored in the parent component and passed to both of the child components that need it.

REACT is Just JavaScript

One of the great things about React is that a lot of what you'll be using is regular JavaScript. Over the past couple of years, functional programming has had a large impact on the JavaScript ecosystem and community. Functional programming is an advanced topic in JavaScript and fills hundreds of books. It's too complex to delve into the benefits of functional programming (we've got to get to React content, right?!?). But React builds on a lot of the techniques of functional programming... techniques that you'll learn as you go through this program. However, there are a couple of important JavaScript functions that are vital to functional programming that we should look at.

the .map() and .filter() methods.

Let's check out the .map() and .filter() Array methods

Array's .map() Method

The JavaScript's Array .map() method gets called on an existing array and returns a new array based what's returned from the function that's passed as an argument:

const names = ['Michael', 'Ryan', 'Tyler'];

const nameLengths = names.map( name => name.length );

Let's go over what's happening here. The .map() method works on arrays, so we have to have an array to start with:

const names = ['Michael', 'Ryan', 'Tyler'];

We call .map() on the names array and pass it a function as an argument:

names.map( name => name.length );
  • The arrow function that's passed to .map() gets called for each item in the names array!
  • The arrow function receives the first name in the array, stores it in the name variable and returns its length.
  • Then it does that again for the remaining two names.
  • .map() returns a new array with the values that are returned from the arrow function:
const nameLengths = names.map( name => name.length );

NOTE: nameLengths will be a new array [7, 4, 5]. This is important to understand; the .map() method returns a new array, it does not modify the original array.

React is Just JavaScript Recap

  • React builds on what you already know — JavaScript!
  • You don't have to learn a special template library or a new way of doing things.
  • Two of the main methods that you'll be using quite a lot are: .map() and .filter().

NOTE: It's important that you're comfortable using these methods, so take some time to practice using them. Why not look through some of your existing code and try converting your for loops to .map() calls or see if you can remove any if statements by using .filter().

Array's .filter() Method

JavaScript's Array .filter() method is similar to the .map() method:

  • it is called on an array
  • it takes a function as an argument
  • it returns a new array The difference is that the function passed to .filter() is used as a test, and only items in the array that pass the test are included in the new array. Let's take a look at an example:
const names = ['Michael', 'Ryan', 'Tyler'];

const shortNames = names.filter( name => name.length < 5 );

Just as before, we have the starting array:

const names = ['Michael', 'Ryan', 'Tyler'];

We call .filter() on the names array and pass it a function as an argument:

names.filter( name => name.length < 5 );

Again, just like with .map() the arrow function that's passed to .filter() gets called for each item in the names array. The first item (i.e. 'Michael') is stored in the name variable. Then the test is performed - this is what's doing the actual filtering. It checks the length of the name. If it's 5 or greater, then it's skipped (and not included in the new array!). But if the length of the name is less than 5, then name.length < 5 returns true and the name is included in the new array!

And lastly, just like with .map() the .filter() method returns a new array instead of modifying the original array:

const shortNames = names.filter( name => name.length < 5 );

So shortNames will be the new array ['Ryan']. Notice that it only has one name in it now, because both 'Michael' and 'Tyler' are 5 characters or longer and were filtered out.

This was just a brief overview of how the .filter() method works.

Combining .map() And .filter() Together

What makes .map() and .filter() so powerful is that they can be combined. Because both methods return arrays, we can chain the method calls together so that the returned data from one can be a new array for the next.

const names = ['Michael', 'Ryan', 'Tyler'];
const shortNamesLengths = names.filter( name => name.length < 5 ).map( name => name.length );

To break it down:

  • the names array is filtered, which returns a new array,
  • but then .map() is called on that new array,
  • and returns a new array of its own!
  • This new array that's returned from .map() is what's stored in shortNamesLengths.

.filter() First!

On a side note, you'll want to run things in this order (.filter() first and then .map()). Because .map() runs the function once for each item in the array, it will be faster if the array were already filtered.

.filter() and .map() Quiz

  • Using the same music data, use .filter() and .map() to filter and map over the list and store the result in a variable named popular. - Use .filter() to filter the list down to just the albums that have sold over 1,000,000 copies.
  • Then chain .map() onto the returned array to create a new array that contains items in the format:
<artist> is a great performer

Filter & Map Quiz Solution Code

Once you've tried your hand at solving this quiz, hover your mouse here for one possible solution.

React is Just JavaScript Recap

  • React builds on what you already know — JavaScript!
  • You don't have to learn a special template library or a new way of doing things.
  • Two of the main methods that you'll be using quite a lot are: .map()and .filter().

NOTE: It's important that you're comfortable using these methods, so take some time to practice using them.

  • Look through some of your existing code and try converting your for loops to .map() calls
  • or see if you can remove any if statements by using .filter().

SUMMARY: Why React:

    1. its compositional model
    1. its declarative nature
    1. the way data flows from parent to child
    1. and that React is really just JavaScript

Resources

  • Virtual DOM - React Docs
  • The Virtual DOM reflects a tree in which each node is an HTML element. React is able to traverse and carry out operations on this Virtual DOM, saving our app from having "costly" activity on the actual DOM.
  • Diffing Algorithm - React Docs
  • Diffing determines how to make efficient changes to the DOM. With diffing, old DOM nodes are taken out and replaced only when necessary. This way, our app doesn't perform any unnecessary operations to figure out when to render content.