From d2cddb4f6aa92cd611cf4e724aa96f3483fb845e Mon Sep 17 00:00:00 2001 From: cassandraGoose Date: Mon, 5 Jun 2023 12:00:47 -0600 Subject: [PATCH 1/5] create legacy class lesson; create prework; update index links --- lessons/index.html | 3 +- .../react-class-components-prework.md | 296 ++++++++++++++ lessons/module-3/react-class-components.md | 360 ++++++++++++++++++ 3 files changed, 657 insertions(+), 2 deletions(-) create mode 100644 lessons/module-3/react-class-components-prework.md create mode 100644 lessons/module-3/react-class-components.md diff --git a/lessons/index.html b/lessons/index.html index a682d9f45..3332c02aa 100644 --- a/lessons/index.html +++ b/lessons/index.html @@ -241,8 +241,7 @@

React Router

Advanced React

diff --git a/lessons/module-3/react-class-components-prework.md b/lessons/module-3/react-class-components-prework.md new file mode 100644 index 000000000..2018f6192 --- /dev/null +++ b/lessons/module-3/react-class-components-prework.md @@ -0,0 +1,296 @@ +--- +title: Class Component Prework - Classes in JavaScript +module: 3 +--- + +## Learning Goals + +By the end of this lesson, you will be able to: + +* explain what a class is +* define classes using the `class` keyword +* create object instances +* call methods on object instances + +## Vocabulary +- `this` - a keyword with a value that changes depending on the context in which it's used +- `class` - a special function which functionas as a template for creating objects +- `object instance` - objects that were created from a class and contain the data and functionality defined in that class +- `inheritance` - a mechanism which derives a class from another class; one class can inherit properties and functionality from a parent class + +## Warm Up + +Answer the following questions. Look at the answers below only after answering on your own: +- What do you know about methods on objects? +- What do you know about the `this` keyword? + +Then, complete [this replit](https://replit.com/@frontend-instructors/Class-Component-Prework-M3#index.js) to review key concepts about object methods and `this`. + +
+ +### Here's how your answers might look. Don't look until you're done! +- What do you know about methods on objects? + + - Objects can have all kinds of properties, such as a function. This function would be called a method. + - You can call functions on objects using dot notation. This is known as calling a method. + - You can create them in several ways, such as: + ```js + const obj = { + methodName: function() { + // Method implementation + } + }; + + // OR + + const obj = { + methodName() { + // Method implementation + } + }; + + // OR + + const obj = { + methodName: () => { + // Method implementation + } + }; + + // ETC + ``` +- What do you know about the `this` keyword? + - By default, this refers to the global object (or in the browser, the window). + - this within function code invoked using the new operator refers to the new instance of that object. + - When executing a function as a method on an object, this refers to that object. + + Replit answers: + + ```js + // 1. + animal.makeSound('Bark!'); + + // 2. + // no answer since this is open ended. + + // 3. + // It should return 5, since 20-15 is 5. + // this.capacity is 20 + // this.attendeeCount is 15 + // this refers the object 'networkingEvent' + ``` +
+ + +## Classes + +Classes serve as object factories that allow us to create multiple objects of the same type, which are commonly referred to as object instances. In other words, a class is a an object template. + +The syntax for defining a class is as follows: + +```js +class NameOfClass { + constructor() { + // define properties here + } + // define methods here +} +``` + +```js +class User { + constructor() { + name = 'Bill', + age = 32, + email = 'bill@gmail.com', + } + + updateAge() { + // we'll talk about what's going on here later. + this.age = this.age++; + } +} +``` + +Please note the use of the `class` keyword and the function `constructor`. The `constructor` function is a special function that gets called when an object instance is created. It's job is to create the same properties on the new object instances we create with our class. + +Next, let's take a look at how to create an object using a class - or 'create an instance' of a class. + +```js +const newObjectInstance = new NameOfClass(); + +const bill = new user(); +``` + +## Making objects dynamic +The constructor function can accept arguments, which allows the class to have dynamic properties. For example: + +```js +class User { + constructor(name, age, email) { + name = name, + age = age, + email = email + } +} +``` + +Now, we can make multiple users and give them all their own names, ages, and emails. + +```js +const jenny = new User('Jenny', 24, 'frogperson@aol.com'); +const bill = new User('Bill', 33, 'bill@gmail.com'); +const alfred = new User('Alfred', 56, 'al888@hotmail.com'); +``` + +## Practice + +```js +class User { + constructor(name, age, email) { + name = name, + age = age, + email = email + } + + updateAge() { + this.age = this.age++; + } + + updateEmail(newEmail) { + this.email = newEmail; + } +} +``` + +Before writing any code, answer the following question. +- Why do we use the `this` keyword in the methods `updateAge` and `updateEmail`? (Feel free to do some research to help you answer this question.) + +Write the following code in a replit, the devtools console, or somewhere else comfortable. Once you're done, feel free to reference the answers below. + +- Based on the class definition above, create a new instance of a user. +- Using what you already know about objects and methods, utilize the object instance you just created and update the user's age. +- Using what you already know about objects and methods, utilize the object instance you just created and update the user's email address. + +Tip: use console logs to check that everything is working as you expect. + +
+ +### A solution _might_ look something like: + +```js +const henrietta = new User('Henrietta', 40, 'h@gmail.com'); + +henrietta.updateAge(); +henrietta.updateEmail('newemail@gmail.com'); +``` +
+ +## More Practice + +Define a class of your own choice. Make sure it has some properties and at least one method. + +To test it out, instantiate the class (make an object instance). + +## Inheritance + +Sometimes, you'll have several classes that are very similar. They may have the same properties or the same functionality. We should work to DRY up our classes, just like we do with any other code. Consider the following class definitions: + +```js +class Animal { + constructor(type, species, weight) { + type = type, + species = species, + weight = weight, + } + + makeSound(sound) { + console.log(sound); + } +} +``` + +```js +class Dog { + constructor(weight, breed) { + type = 'Mammal', + species = 'Canine', + weight = weight, + breed = breed, + } + + bark() { + console.log('woof!'); + } +} +``` + +- What are all the similarities you see between these two classes? +- How does a 'dog' relate to the category of 'animal' in real life? + +
+ +### Possible answers to the above questions: + +Some similarities between the two classes are: + +- similar properties: type, species, weight +- similar method: both the method makeSound and bark are doing the same thing. + +A dog is a type of animal in real life. A dog could be considered a subcategory of the animal category. +
+ +This is a perfect time to implement inheritance. Instead of repeating ourselves so much, we can make the Dog class _inherit_ the properties it needs from the Animal class. Then, we could even make more classes that inherit from Animal, such as Cat or Llama. + +We can make a class inherit from a parent class by using the `extends` keyword. We can then call the constructor of the parent class, which will give the Dog class access to the Animal's properties and methods by calling the `super` function. + +```js +class Animal { + constructor(type, species, weight) { + this.type = type; + this.species = species; + this.weight = weight; + } + + makeSound(sound) { + console.log(sound); + } +} + +class Dog extends Animal { + constructor(type, species, weight, breed) { + super(type, species, weight); + this.breed = breed; + } +} + +const fido = new Dog('Mammal', 'Canine', 10, 'Yorkshire Terrier'); +fido.makeSound('Woof!'); + +``` + +
+### Fun Fact + +OOP, or Object Oriented Programming, is a programming paradigm based on classes and objects. In JS, you would utilize classes if you wrote your code in an OOP style. + +We've been primarily working in a more functional programming paradigm throughout this program. + +If you're interested in learning more, please research the differences between functional and object oriented programming. +
+ +
+ +### Checks for Understanding + +* What is a class? +* How do you define a class in code? +* How do you create an object instance using a class? +* How do you call a method on an object instance? +
+ +### Resources: + - [Classes: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) + - [Class Practice](https://github.com/turingschool/dogs-and-dog-parks) + - [More Class Practice](https://github.com/turingschool/wills-lunchbox) + - [OOP vs Functional](https://careerfoundry.com/en/blog/web-development/functional-programming-vs-oop/) \ No newline at end of file diff --git a/lessons/module-3/react-class-components.md b/lessons/module-3/react-class-components.md new file mode 100644 index 000000000..dab362dca --- /dev/null +++ b/lessons/module-3/react-class-components.md @@ -0,0 +1,360 @@ +--- + +title: Legacy Class Components in React +module: 3 + +--- + +
+ +### Prework + +Understanding class components requires some background knowledge about classes in JavaScript. Please complete the following pre-work before the lesson. + +[Classes in JavaScript](./react-class-components-prework.html) + +
+ +## Learning Goals + +By the end of this lesson, you will be able to: + +* explain the differences between classs components and functional components +* create class components +* convert class based components to functional components + +## Vocabulary +- `this` - a keyword with a value that changes depending on the context in which it's used +- `class` - a special function which acts as as a template for creating objects +- `inheritance` - a mechanism which derives a class from another class; one class can inherit properties and functionality from a parent class +- `class component` - a React component that inherits properties and methods from a `Component` class. + +
+ +## Warm Up + +In small groups, answer the following questions. Make sure everyone has an oportunity to share and feel free to share screens. +- What do you know about JS classes? +- In your own words, desribe what inheritance is. +- How do you create a class in JS? +- How do you create an object instance using a class? + +
+ +## Getting Started + +We’re going to be using this [ideabox](https://github.com/turingschool-examples/react-iii-ideabox) repo today. Before going any further please do the following: +* Clone the repo to your machine +* Switch to the `refactor-hooks-to-classes` branch +* Run `npm install` in the repo +* Put a thumbs up in the participants panel of zoom once you’re done! + +## Background + +React has been around since 2013 and that means it has gone through many iterations. Originally, if a developer wanted to utilize state and utilize a component's lifecycle then they had to use a class component. More recently, React introduced Hooks. Hooks allow developers to use state and a component's lifecycle in a functional component. This pattern is encouraged as common practice moving forward. + +However, enterprise and company software moves at a much slower pace than the React ecosystem. This means that there are still many code bases out there that are using class components. You might find yourself in a job which uses class components! You may also find yourself tasked with the job of refactoring legacy class components into functional components. + +## Compare and Contrast + +Both functional and class components share some common features: +- they both render JSX in some way +- they both can have props +- the both can have state +- they both have a way to call functions at different stages of a component's life-cycle. (for example, `useEffect`) + +The main differences are: +- things work differently under the hood +- the syntax is different! + +## React Class Components + +#### What are class components anyway? + +Class components, or class-based components, are just JavaScript classes that act as independent and reusable bits of code which allow you to render content to the DOM. A class component inherits methods and properties from a parent class which React provides, using the `extend` keyword. We'll take a look at more of these inherited properties and methods later. For now, let's take a look at an example of a class component, which has a `render` method and renders content to the DOM - similar to how a functional component renders content with the `return` keyword. + +```jsx +import { Component } from 'react'; + +export default class App extends Component { + render() { + return ( +
+ Hello, World! +
+ ) + } +} +``` + +
+ +### Tip + +Render should only return JSX. Avoid doing anything else in this method - there should be no side-effects. This isn't a good place to update state or run any operations. + +
+ +## State in Class Components + +Instead of using hooks to define and update state, class components utilize class properties and a class method. To utilize the parent class' properties and methods, we must call the `super` function. This will give us access to a method called `setState`, which we can use to update our state. After that, we can define our state using the `this` keyword. Note: state must be an object, but you can have other data types inside of it. + +You can access state in your render method by referencing `this`. + +```jsx +import { Component } from 'react'; + +class App extends Component { + constructor() { + super(); + this.state = { + name: 'Bill', + } + } + + render() { + return { +

Hello, {this.state.name}

+ } + } +} +``` + +### Props in Class Components + +Props probably look similar to what you're used to in functional components. How we use them _within_ our components must change a little bit, though. + +You can pass props to a component. + +```js + + + +``` + +To access props in a class component, lean on your good friend `this`: + +```js +import { Component } from 'react'; + +class UserComponent extends Component { + render() { + return

Email: { this.props.email }

; + } +} +``` + +## Event Handlers + +Event handlers may look a bit different in class based components, but only because we have to utilize `this` to call methods from our class. + +For example: + +```jsx +import { Component } from 'react'; + +class App extends Component { + constructor() { + super(); + this.state = { + description: '', + title: '' + } + } + + handleChange = event => { + this.setState({ [event.target.name ]: event.target.value }); + } + + render() { + return ( +
+ this.handleChange(event)} + /> + this.handleChange(event)} + /> + +
+ ) +} + +``` + +
+ +### For your consideration: + +It's common to define event handlers with arrow functions. Why do you think that is? + +
+ +
+ +### Your turn! + +Use your new class component knowledge to begin refactoring the Form in the Ideabox repository into a functional component. Work with a partner to do the following: + +- import the `useState` hook from the React library +- refactor the class based component into a functional component of the same name +- remove the old constructor, and replace it with calls to the useState hook (make sure to name both your new piece of state, and the function that will update it) +- update your render method into a return statement to make use of your new state and setter methods +- NOTE: The current form makes use of a handleChange method. You don’t necessarily need this, but you can use it with some appropriate refactoring. + +
+ +
+ +### Here's one way you could do it, don't look until you're done! + +```jsx +import { useState } from 'react'; +import './Form.css'; + +function Form(props) { + const [title, setTitle] = useState('') + const [description, setDescription] = useState('') + + const submitIdea = event => { + event.preventDefault(); + const newIdea = { + id: Date.now(), + title, + description + } + props.addIdea(newIdea); + clearInputs(); + } + + const clearInputs = () => { + setTitle('') + setDescription('') + } + + return ( +
+ setTitle(event.target.value)} + /> + + setDescription(event.target.value)} + /> + + +
+ ) +} + +export default Form; + +``` + +
+ +## Lifecycle Methods + +In functional components, you can call functions in response to the lifecycle of a component using the `useEffect` hook. + +Review the following questions before diving into Lifecycle methods for class components: + +- How do you call a function when the component mounts using `useEffect`? +- How do you call a function when state changes using `useEffect`? + +Class components inherit several lifecycle methods that we can use. Two important methods are: + +`componentDidMount` - this method is invoked immediately after a component is mounted + +`componentDidUpdate()` - this method is invoked _after_ updating occurs. It is not called on the initial render. This is a good place for network requests and updating state, but you'll need to compare the current props to the previous props. Find more information [here](https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en) to learn about using a conditional to update state in `componentDidUpdate` so that you don't end up with an infinite loop. + +
+ +### Your turn! + +With a partner, refactor the App component in our ideabox to be a functional component. Make sure you do the following: + +- import `useState` and `useEffect` from the react library +- convert the class based component into a functional component +- use the `useState` hook to recreate the parts of state that were previously in a constructor function +- use the `useEffect` hook to recreate the functionality present in the lifecycle method +- update the return statement using your new state values + +If you’ve done everything right, the ideabox should still work exactly as it did before! + +
+ + +
+ +### Here's one way you could do it, don't look until you're done! + +```jsx +import { useState, useEffect } from 'react'; +import Ideas from './Ideas'; +import Form from './Form'; +import './App.css'; + +function App() { + const [ideas, setIdeas] = useState([]) + + useEffect(() => { + document.title = `Ideabox (${ideas.length})` + }) + + const addIdea = (newIdea) => { + setIdeas([...ideas, newIdea]); + } + + const deleteIdea = (id) => { + const filteredIdeas = ideas.filter(idea => idea.id !== id); + + setIdeas(filteredIdeas); + } + + return( +
+

IdeaBox

+
+ +
+ ) +} + +export default App; +``` + +
+ +
+ +### Checks for Understanding + +* What's the difference between class components and functional components in React? +* What is `componentDidMount` used for? +* How do you work with state in a class component? +* Why is it useful to know about class components? + +
+ +### Resources + +- [Legacy React Docs](https://legacy.reactjs.org/) +- [How to use componentDidUpdate](https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en) +- [Tips for converting a class component into a functional one in React](https://www.petroskyriakou.com/tips-for-converting-a-class-component-to-a-functional-one-in-react) \ No newline at end of file From 6f2c87fb53d31db9d7e02cce5407d48a64f12f4b Mon Sep 17 00:00:00 2001 From: cassandraGoose Date: Mon, 5 Jun 2023 12:04:10 -0600 Subject: [PATCH 2/5] remove note in code example --- lessons/module-3/react-class-components-prework.md | 1 - 1 file changed, 1 deletion(-) diff --git a/lessons/module-3/react-class-components-prework.md b/lessons/module-3/react-class-components-prework.md index 2018f6192..bcfad2d2a 100644 --- a/lessons/module-3/react-class-components-prework.md +++ b/lessons/module-3/react-class-components-prework.md @@ -106,7 +106,6 @@ class User { } updateAge() { - // we'll talk about what's going on here later. this.age = this.age++; } } From 2efc1b49d15c19016a9cbb909c4bff3c3528c565 Mon Sep 17 00:00:00 2001 From: cassandraGoose Date: Mon, 5 Jun 2023 14:38:18 -0600 Subject: [PATCH 3/5] fix typos and add note about React invoking lifecycle methods for us along with a fun fact about method overriding, because why not --- lessons/module-3/react-class-components-prework.md | 4 ++-- lessons/module-3/react-class-components.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lessons/module-3/react-class-components-prework.md b/lessons/module-3/react-class-components-prework.md index bcfad2d2a..c4fb93329 100644 --- a/lessons/module-3/react-class-components-prework.md +++ b/lessons/module-3/react-class-components-prework.md @@ -111,14 +111,14 @@ class User { } ``` -Please note the use of the `class` keyword and the function `constructor`. The `constructor` function is a special function that gets called when an object instance is created. It's job is to create the same properties on the new object instances we create with our class. +Please note the use of the `class` keyword and the function `constructor`. The `constructor` function is a special function that gets called when an object instance is created. Its job is to create the same properties on the new object instances we create with our class. Next, let's take a look at how to create an object using a class - or 'create an instance' of a class. ```js const newObjectInstance = new NameOfClass(); -const bill = new user(); +const bill = new User(); ``` ## Making objects dynamic diff --git a/lessons/module-3/react-class-components.md b/lessons/module-3/react-class-components.md index dab362dca..2323738b6 100644 --- a/lessons/module-3/react-class-components.md +++ b/lessons/module-3/react-class-components.md @@ -280,7 +280,7 @@ Review the following questions before diving into Lifecycle methods for class co Class components inherit several lifecycle methods that we can use. Two important methods are: -`componentDidMount` - this method is invoked immediately after a component is mounted +`componentDidMount` - this method is invoked immediately after a component is mounted. React invokes this for us - we simply define the method in our class component. Note: the action of defining `componentDidMount` is actually something fancy called `method overwriting`, which allows a child class to make a specific implementation of the parent class' method. `componentDidUpdate()` - this method is invoked _after_ updating occurs. It is not called on the initial render. This is a good place for network requests and updating state, but you'll need to compare the current props to the previous props. Find more information [here](https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en) to learn about using a conditional to update state in `componentDidUpdate` so that you don't end up with an infinite loop. From ee42e0003b9eb4241fbb829751392db805dba94c Mon Sep 17 00:00:00 2001 From: cassandraGoose Date: Mon, 5 Jun 2023 14:38:48 -0600 Subject: [PATCH 4/5] add note about react invoking this for us for componentDidUpdate as well --- lessons/module-3/react-class-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/module-3/react-class-components.md b/lessons/module-3/react-class-components.md index 2323738b6..552b21810 100644 --- a/lessons/module-3/react-class-components.md +++ b/lessons/module-3/react-class-components.md @@ -282,7 +282,7 @@ Class components inherit several lifecycle methods that we can use. Two importan `componentDidMount` - this method is invoked immediately after a component is mounted. React invokes this for us - we simply define the method in our class component. Note: the action of defining `componentDidMount` is actually something fancy called `method overwriting`, which allows a child class to make a specific implementation of the parent class' method. -`componentDidUpdate()` - this method is invoked _after_ updating occurs. It is not called on the initial render. This is a good place for network requests and updating state, but you'll need to compare the current props to the previous props. Find more information [here](https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en) to learn about using a conditional to update state in `componentDidUpdate` so that you don't end up with an infinite loop. +`componentDidUpdate()` - this method is invoked _after_ updating occurs. It is not called on the initial render. React invokes this for us, as well. This is a good place for network requests and updating state, but you'll need to compare the current props to the previous props. Find more information [here](https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en) to learn about using a conditional to update state in `componentDidUpdate` so that you don't end up with an infinite loop.
From e8cf563e0e3bc4b0c9f0381a4ec412d3de056cc4 Mon Sep 17 00:00:00 2001 From: cassandraGoose Date: Fri, 9 Jun 2023 11:28:02 -0600 Subject: [PATCH 5/5] remove inheritance stuff --- .../react-class-components-prework.md | 78 ------------------- lessons/module-3/react-class-components.md | 2 - 2 files changed, 80 deletions(-) diff --git a/lessons/module-3/react-class-components-prework.md b/lessons/module-3/react-class-components-prework.md index c4fb93329..1e2fb729d 100644 --- a/lessons/module-3/react-class-components-prework.md +++ b/lessons/module-3/react-class-components-prework.md @@ -16,7 +16,6 @@ By the end of this lesson, you will be able to: - `this` - a keyword with a value that changes depending on the context in which it's used - `class` - a special function which functionas as a template for creating objects - `object instance` - objects that were created from a class and contain the data and functionality defined in that class -- `inheritance` - a mechanism which derives a class from another class; one class can inherit properties and functionality from a parent class ## Warm Up @@ -191,83 +190,6 @@ Define a class of your own choice. Make sure it has some properties and at least To test it out, instantiate the class (make an object instance). -## Inheritance - -Sometimes, you'll have several classes that are very similar. They may have the same properties or the same functionality. We should work to DRY up our classes, just like we do with any other code. Consider the following class definitions: - -```js -class Animal { - constructor(type, species, weight) { - type = type, - species = species, - weight = weight, - } - - makeSound(sound) { - console.log(sound); - } -} -``` - -```js -class Dog { - constructor(weight, breed) { - type = 'Mammal', - species = 'Canine', - weight = weight, - breed = breed, - } - - bark() { - console.log('woof!'); - } -} -``` - -- What are all the similarities you see between these two classes? -- How does a 'dog' relate to the category of 'animal' in real life? - -
- -### Possible answers to the above questions: - -Some similarities between the two classes are: - -- similar properties: type, species, weight -- similar method: both the method makeSound and bark are doing the same thing. - -A dog is a type of animal in real life. A dog could be considered a subcategory of the animal category. -
- -This is a perfect time to implement inheritance. Instead of repeating ourselves so much, we can make the Dog class _inherit_ the properties it needs from the Animal class. Then, we could even make more classes that inherit from Animal, such as Cat or Llama. - -We can make a class inherit from a parent class by using the `extends` keyword. We can then call the constructor of the parent class, which will give the Dog class access to the Animal's properties and methods by calling the `super` function. - -```js -class Animal { - constructor(type, species, weight) { - this.type = type; - this.species = species; - this.weight = weight; - } - - makeSound(sound) { - console.log(sound); - } -} - -class Dog extends Animal { - constructor(type, species, weight, breed) { - super(type, species, weight); - this.breed = breed; - } -} - -const fido = new Dog('Mammal', 'Canine', 10, 'Yorkshire Terrier'); -fido.makeSound('Woof!'); - -``` -
### Fun Fact diff --git a/lessons/module-3/react-class-components.md b/lessons/module-3/react-class-components.md index 552b21810..2cc209c86 100644 --- a/lessons/module-3/react-class-components.md +++ b/lessons/module-3/react-class-components.md @@ -26,7 +26,6 @@ By the end of this lesson, you will be able to: ## Vocabulary - `this` - a keyword with a value that changes depending on the context in which it's used - `class` - a special function which acts as as a template for creating objects -- `inheritance` - a mechanism which derives a class from another class; one class can inherit properties and functionality from a parent class - `class component` - a React component that inherits properties and methods from a `Component` class.
@@ -35,7 +34,6 @@ By the end of this lesson, you will be able to: In small groups, answer the following questions. Make sure everyone has an oportunity to share and feel free to share screens. - What do you know about JS classes? -- In your own words, desribe what inheritance is. - How do you create a class in JS? - How do you create an object instance using a class?