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..1e2fb729d --- /dev/null +++ b/lessons/module-3/react-class-components-prework.md @@ -0,0 +1,217 @@ +--- +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 + +## 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() { + 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. 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(); +``` + +## 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). + +
+### 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..2cc209c86 --- /dev/null +++ b/lessons/module-3/react-class-components.md @@ -0,0 +1,358 @@ +--- + +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 +- `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? +- 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. 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. 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. + +
+ +### 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