From 19227b5a0115c47de4dde2168d71af8b0f52a919 Mon Sep 17 00:00:00 2001 From: mclilzee <70924991+Mclilzee@users.noreply.github.com> Date: Mon, 25 Dec 2023 06:14:55 +0100 Subject: [PATCH 001/111] Remove words nodeJS --- nodeJS/apis/api_basics.md | 6 +- nodeJS/apis/api_security.md | 2 +- nodeJS/apis/project_blog_api.md | 2 +- .../authentication/authentication_basics.md | 76 +++++++++---------- nodeJS/authentication/project_members_only.md | 2 +- .../authentication/security_configuration.md | 2 +- nodeJS/express_and_mongoose/deployment.md | 12 +-- nodeJS/express_and_mongoose/express_101.md | 10 +-- .../express_102_crud_and_mvc.md | 10 +-- .../express_103_routes_and_controllers.md | 2 +- .../introduction_to_express.md | 4 +- .../project_mini_message_board.md | 2 +- nodeJS/final_project/project_odin_book.md | 65 +++++++--------- .../introduction_what_is_nodeJS.md | 4 +- .../project_basic_informational_site.md | 2 +- .../testing_database_operations.md | 8 +- .../testing_routes_and_controllers.md | 6 +- 17 files changed, 103 insertions(+), 112 deletions(-) diff --git a/nodeJS/apis/api_basics.md b/nodeJS/apis/api_basics.md index d064a7f40af..e3b790ff43b 100644 --- a/nodeJS/apis/api_basics.md +++ b/nodeJS/apis/api_basics.md @@ -16,9 +16,9 @@ By the end of this lesson, you should be able to do the following: In recent years, a new pattern for developing websites has been gaining popularity. Instead of creating an app that hosts both the database and view templates, many developers are separating these concerns into separate projects, hosting their backend and database on a server (either on something like [Heroku](https://www.heroku.com/) or on a VPS like [Digital Ocean](https://www.digitalocean.com/)), then using a service such as [GitHub Pages](https://pages.github.com/) or [Netlify](https://www.netlify.com/) to host their frontend. This technique is sometimes referred to as the [Jamstack](https://jamstack.org/what-is-jamstack/). -Organizing your project this way can be beneficial because it allows your project to be more modular instead of combining business logic with view logic. This also allows you to use a single backend source for multiple frontend applications, such as a website, a desktop app, or a mobile app. Other developers enjoy this pattern because they simply like using frontend frameworks such as React or Vue to create nice frontend-only, single-page applications. +Organizing your project this way can be beneficial because it allows your project to be more modular instead of combining business logic with view logic. This also allows you to use a single backend source for multiple frontend applications, such as a website, a desktop app, or a mobile app. Other developers enjoy this pattern because they like using frontend frameworks such as React or Vue to create nice frontend-only, single-page applications. -Frontend and backend applications usually talk to each other using JSON, which you have already encountered if you've gone through our frontend JavaScript course. So at this point, all you really need to learn is how to get your Express application to speak JSON instead of HTML, which fortunately for you is extremely simple! The assignment at the end of this lesson will take you through a tutorial, but essentially all you have to do is pass your information into [`res.json()`](https://expressjs.com/en/4x/api.html#res.json) instead of [`res.send()`](https://expressjs.com/en/4x/api.html#res.send) or [`res.render()`](https://expressjs.com/en/4x/api.html#res.render). How easy is that? +Frontend and backend applications usually talk to each other using JSON, which you have already encountered if you've gone through our frontend JavaScript course. So at this point, all you really need to learn is how to get your Express application to speak JSON instead of HTML. The assignment at the end of this lesson will take you through a tutorial, but essentially all you have to do is pass your information into [`res.json()`](https://expressjs.com/en/4x/api.html#res.json) instead of [`res.send()`](https://expressjs.com/en/4x/api.html#res.send) or [`res.render()`](https://expressjs.com/en/4x/api.html#res.render). How easy is that? It is also quite possible to have an Express app that serves both views and JSON by using the Express router to set up different routes. If you think back to the organization of the routes in our Library Tutorial ([here's a link to it](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes#Create_the_catalog_route_module)). All of our routes were set up in a `catalog` module, so to get the view for our list of books you would access `/catalog/books`. Setting the Library project up to also serve JSON would be as easy as creating a different router module called `api` and then adjusting the controllers so that `/catalog/books` would serve up the HTML list of our books and `/api/books` would serve up the same information as JSON. @@ -30,7 +30,7 @@ _However_, it's conventional to follow REST (an acronym for Representational Sta The actual technical definition of REST is a little complicated (you can read about it on [wikipedia](https://en.wikipedia.org/wiki/Representational_state_transfer)), but for our purposes, most of the elements (statelessness, cacheability, etc.) are covered by default just by using Express to output JSON. The piece that we specifically want to think about is how to **organize our endpoint URIs** (Uniform Resource Identifier). REST APIs are resource based, which basically means that instead of having names like `/getPostComments` or `/savePostInDatabase` we refer **directly to the resource** (in this case, the blog post) and use HTTP verbs such as GET, POST, PUT, and DELETE to determine the action. -Typically this takes the form of 2 URI's per resource, one for the whole collection and one for a single object in that collection, for example, you might get a list of blog-posts from `/posts` and then get a specific post from `/posts/:postid`. You can also nest collections in this way. To get the list of comments on a single post you would access `/posts/:postid/comments` and then to get a single comment: `/posts/:postid/comments/:commentid`. Below are some other simple examples of endpoints you could have. +Typically this takes the form of 2 URI's per resource, one for the whole collection and one for a single object in that collection, for example, you might get a list of blog-posts from `/posts` and then get a specific post from `/posts/:postid`. You can also nest collections in this way. To get the list of comments on a single post you would access `/posts/:postid/comments` and then to get a single comment: `/posts/:postid/comments/:commentid`. Below are some other basic examples of endpoints you could have. | Verb | Action | Example | | ------ | ------ | -------------------------------------------------- | diff --git a/nodeJS/apis/api_security.md b/nodeJS/apis/api_security.md index abc7c150e84..6d160f0b49a 100644 --- a/nodeJS/apis/api_security.md +++ b/nodeJS/apis/api_security.md @@ -12,7 +12,7 @@ By the end of this lesson, you should be able to do or answer the following: ### Overview Securing your API is an important step. When we were using Express to serve view templates we used PassportJS along with a username and password to authenticate users, but that is not the only way to secure an Express app, and in the context of an API it often makes sense to use a different strategy. The username and password session pattern that we learned previously will still work of course, though it is made a little more complicated by the fact that we've separated our front-end code from the back-end. -Another strategy is to generate and pass a secure **token** between our back-end and front-end code. Doing so will make sure that our user's username and password are not compromised and will also give us the ability to expire our user's session for added security. The basic idea is that when a user signs in to our app, a secure token is created, and then for all subsequent requests that token is passed in the header of our request object. In the end, the process is pretty simple since you should already be pretty comfortable with using passport to authenticate users. +Another strategy is to generate and pass a secure **token** between our back-end and front-end code. Doing so will make sure that our user's username and password are not compromised and will also give us the ability to expire our user's session for added security. The basic idea is that when a user signs in to our app, a secure token is created, and then for all subsequent requests that token is passed in the header of our request object. In the end, the process is straightforward since you should already be comfortable with using passport to authenticate users. This strategy, while particularly useful with APIs can be used with a traditional view-template project as well. The main difference here is that instead of setting and checking a cookie we're passing a special token in the header of our request. In our previous Authentication Tutorial, the Passport middleware checked the cookie that was sent and then either authenticated or denied our user. In this case, we're going to do something very similar, but instead of using cookies, we're going to pass the token. diff --git a/nodeJS/apis/project_blog_api.md b/nodeJS/apis/project_blog_api.md index 896c85207b5..40d52adb167 100644 --- a/nodeJS/apis/project_blog_api.md +++ b/nodeJS/apis/project_blog_api.md @@ -8,7 +8,7 @@ Why are we setting it up like this? Because we can! If you already have a portfo
1. Begin by designing your back end models and schemas. How you design it is up to you, but you might want to think through a few things: - - For a simple blog with only a single author you might not need a user model, but you might want to set up authentication so that you can protect the editing functions with a username and password. In that case, it might make sense to set up a minimal user model, even if you are the only user. + - For a blog with only a single author you might not need a user model, but you might want to set up authentication so that you can protect the editing functions with a username and password. In that case, it might make sense to set up a minimal user model, even if you are the only user. - Your blog should have posts and comments, so think about the fields you are going to want to include for each of those. - Are you going to require users to leave a username or email with their comments? - Are you going to display a date or a timestamp for posts and comments? diff --git a/nodeJS/authentication/authentication_basics.md b/nodeJS/authentication/authentication_basics.md index 917b2ee9894..93f35b07c7b 100644 --- a/nodeJS/authentication/authentication_basics.md +++ b/nodeJS/authentication/authentication_basics.md @@ -28,9 +28,9 @@ We're going to be using another Mongo database, so before we begin log in to you To begin, let's set up a very minimal express app with a single MongoDB model for our users. Create a new directory and use `npm init` to start the package.json file then run the following to install all the dependencies we need: -``` +~~~ npm install express express-session mongoose passport passport-local ejs -``` +~~~ **Mongoose Update**: With the new 7.0.1 version of Mongoose callbacks are no longer supported when querying a database. A promise will be returned instead, meaning that you will now have to use async/await or promises to achieve the same results. If you need a refresher on async/await you can find it in the [Async And Await Lesson](https://www.theodinproject.com/lessons/node-path-javascript-async-and-await) from the JavaScript Course. As you progress through this lesson you will see a blend of using async/await with try/catch blocks as well as other functions that use callbacks, which you've seen as you've progressed through the NodeJS course. You can read more about this change [here](https://mongoosejs.com/docs/migrating_to_7.html#dropped-callback-support). @@ -38,7 +38,7 @@ Next, let's create our `app.js`: **IMPORTANT NOTE**: For the moment we are saving our users with just a plain text password. This is a _really_ bad idea for any real-world project. At the end of this lesson, you will learn how to properly secure these passwords using bcrypt. Don't skip that part. -```javascript +~~~javascript /////// app.js const express = require("express"); @@ -74,13 +74,13 @@ app.use(express.urlencoded({ extended: false })); app.get("/", (req, res) => res.render("index")); app.listen(3000, () => console.log("app listening on port 3000!")); -``` +~~~ Most of this should look familiar to you by now, except for the new imported middleware for express-session and passport. We are not actually going to be using express-session directly, it is a dependency that is used in the background by passport.js. You can take a look at what it does [here](https://github.com/expressjs/session). -To keep things simple, our view engine is set up to just look in the main directory, and it's looking for a template called `index.ejs` so go ahead and create that: +Our view engine is set up to just look in the main directory, and it's looking for a template called `index.ejs` so go ahead and create that: -```html +~~~html @@ -91,7 +91,7 @@ To keep things simple, our view engine is set up to just look in the main direct

hello world!

-``` +~~~ ### Creating users @@ -99,7 +99,7 @@ The first thing we need is a sign up form so we can actually create users to aut Create a new template called `sign-up-form`, and a route for `/sign-up` that points to it: -```html +~~~html @@ -117,18 +117,18 @@ Create a new template called `sign-up-form`, and a route for `/sign-up` that poi -``` +~~~ -```javascript +~~~javascript //// app.js app.get("/sign-up", (req, res) => res.render("sign-up-form")); -``` +~~~ Next, create an `app.post` for the sign up form so that we can add users to our database (remember our notes about sanitation, and using plain text to store passwords...). -```javascript +~~~javascript app.post("/sign-up", async (req, res, next) => { try { const user = new User({ @@ -141,7 +141,7 @@ app.post("/sign-up", async (req, res, next) => { return next(err); }; }); -``` +~~~ Let's reiterate: this is not a particularly safe way to create users in your database... BUT you should now be able to visit `/sign-up`, and submit the form. If all goes well it'll redirect you to the index and you will be able to go see your newly created user inside your database. @@ -154,7 +154,7 @@ Now that we have the ability to put users in our database, let's allow them to l We need to add 3 functions to our app.js file, and then add an app.post for our `/log-in` path. Add them somewhere before the line that initializes passport for us: `app.use(passport.initialize())`. #### Function one : setting up the LocalStrategy -```javascript +~~~javascript passport.use( new LocalStrategy(async (username, password, done) => { try { @@ -171,7 +171,7 @@ passport.use( }; }) ); -``` +~~~ This function is what will be called when we use the `passport.authenticate()` function later. Basically, it takes a username and password, tries to find the user in our DB, and then makes sure that the user's password matches the given password. If all of that works out (there's a user in the DB, and the passwords match) then it authenticates our user and moves on! We will not be calling this function directly, so you won't have to supply the `done` function. This function acts a bit like a middleware and will be called for us when we ask passport to do the authentication later. @@ -179,7 +179,7 @@ This function is what will be called when we use the `passport.authenticate()` f To make sure our user is logged in, and to allow them to _stay_ logged in as they move around our app, passport will use some data to create a cookie which is stored in the user's browser. These next two functions define what bit of information passport is looking for when it creates and then decodes the cookie. The reason they require us to define these functions is so that we can make sure that whatever bit of data it's looking for actually exists in our Database! For our purposes, the functions that are listed in the passport docs will work just fine. -```javascript +~~~javascript passport.serializeUser((user, done) => { done(null, user.id); }); @@ -192,15 +192,15 @@ passport.deserializeUser(async (id, done) => { done(err); }; }); -``` +~~~ Again, we aren't going to be calling these functions on our own, they're used in the background by passport. ### Log in form -To keep things nice and simple let's go ahead and add the login form directly to our index template. The form will look just like our sign-up form, but instead of `POST`ing to `/sign-up` we'll add an `action` to it so that it `POST`s to `/log-in` instead. Add the following to your index template: +Let's go ahead and add the login form directly to our index template. The form will look just like our sign-up form, but instead of `POST`ing to `/sign-up` we'll add an `action` to it so that it `POST`s to `/log-in` instead. Add the following to your index template: -```html +~~~html

please log in

@@ -209,11 +209,11 @@ To keep things nice and simple let's go ahead and add the login form directly to
-``` +~~~ ... and now for the magical part! Add this route to your app.js file: -```javascript +~~~javascript app.post( "/log-in", passport.authenticate("local", { @@ -221,7 +221,7 @@ app.post( failureRedirect: "/" }) ); -``` +~~~ As you can see, all we have to do is call `passport.authenticate()`. This middleware performs numerous functions behind the scenes. Among other things, it looks at the request body for parameters named `username` and `password` then runs the `LocalStrategy` function that we defined earlier to see if the username and password are in the database. It then creates a session cookie that gets stored in the user's browser, and that we can access in all future requests to see whether or not that user is logged in. It can also redirect you to different routes based on whether the login is a success or a failure. If we had a separate login page we might want to go back to that if the login failed, or we might want to take the user to their user dashboard if the login is successful. Since we're keeping everything in the index we want to go back to "/" no matter what. @@ -231,15 +231,15 @@ The passport middleware checks to see if there is a user logged in (by checking Edit your `app.get("/")` to send the user object to our view like so: -```javascript +~~~javascript app.get("/", (req, res) => { res.render("index", { user: req.user }); }); -``` +~~~ and then edit your view to make use of that object like this: -```html +~~~html @@ -262,13 +262,13 @@ and then edit your view to make use of that object like this: <%}%> -``` +~~~ So, this code checks to see if there is a user defined... if so it offers a welcome message, and if NOT then it shows the login form. Neat! -As one last step... let's make that log out link actually work for us. As you can see it's simply sending us to `/log-out` so all we need to do is add a route for that in our app.js. Conveniently, the passport middleware adds a logout function to the `req` object, so logging out is as easy as this: +As one last step... let's make that log out link actually work for us. As you can see it's sending us to `/log-out` so all we need to do is add a route for that in our app.js. Conveniently, the passport middleware adds a logout function to the `req` object, so logging out is as easy as this: -```javascript +~~~javascript app.get("/log-out", (req, res, next) => { req.logout((err) => { if (err) { @@ -277,7 +277,7 @@ app.get("/log-out", (req, res, next) => { res.redirect("/"); }); }); -``` +~~~ You should now be able to visit `/sign-up` to create a new user, then log-in using that user's username and password, and then log out by clicking the log out button! @@ -285,20 +285,20 @@ You should now be able to visit `/sign-up` to create a new user, then log-in usi In express, you can set and access various local variables throughout your entire app (even in views) with the `locals` object. We can use this knowledge to write ourselves a custom middleware that will simplify how we access our current user in our views. -Middleware functions are simply functions that take the `req` and `res` objects, manipulate them, and pass them on through the rest of the app. +Middleware functions are functions that take the `req` and `res` objects, manipulate them, and pass them on through the rest of the app. -```javascript +~~~javascript app.use((req, res, next) => { res.locals.currentUser = req.user; next(); }); -``` +~~~ If you insert this code somewhere between where you instantiate the passport middleware and before you render your views, you will have access to the `currentUser` variable in all of your views, and you won't have to manually pass it into all of the controllers in which you need it. ### Securing passwords with bcrypt -Now, let's go back and learn how to securely store user passwords so that if anything ever goes wrong, or if someone gains access to our database, our user passwords will be safe. This is _insanely_ important, even for the simplest apps, but luckily it's also really simple to set up. +Now, let's go back and learn how to securely store user passwords so that if anything ever goes wrong, or if someone gains access to our database, our user passwords will be safe. This is _insanely_ important, even for the most basic apps. First `npm install bcryptjs`. There is another module called `bcrypt` that does the same thing, but it is written in C++ and is sometimes a pain to get installed. The C++ `bcrypt` is technically faster, so in the future it might be worth getting it running, but for now, the modules work the same so we can just use `bcryptjs`. @@ -310,18 +310,18 @@ Password hashes are the result of passing the user's password through a one-way Edit your `app.post("/sign-up")` to use the bcrypt.hash function which works like this: -```javascript +~~~javascript bcrypt.hash(req.body.password, 10, async (err, hashedPassword) => { // if err, do something // otherwise, store hashedPassword in DB }); -``` +~~~ The second argument is the length of the "salt" to use in the hashing function; salting a password means adding extra random characters to it, the password plus the extra random characters are then fed into the hashing function. Salting is used to make a password hash output unique, even for users who use the same password, and to protect against [rainbow table](https://en.wikipedia.org/wiki/Rainbow_table) and [dictionary](https://en.wikipedia.org/wiki/Dictionary_attack) attacks. Usually, the salt gets stored in the database in the clear next to the hashed value, but in our case, there is no need to do so because the hashing algorithm that `bcryptjs` uses includes the salt automatically with the hash. -The hash function is somewhat slow, so all of the DB storage stuff needs to go inside the callback. Check to see if you've got this working by signing up a new user with a simple password, then go look at your DB entries to see how it's being stored. If you've done it right, your password should have been transformed into a really long random string. +The hash function is somewhat slow, so all of the DB storage stuff needs to go inside the callback. Check to see if you've got this working by signing up a new user with a password, then go look at your DB entries to see how it's being stored. If you've done it right, your password should have been transformed into a really long random string. It's important to note that _how_ hashing works is beyond the scope of this lesson. To learn more about the subject consider reading [This wikipedia article](https://en.wikipedia.org/wiki/Cryptographic_hash_function). @@ -331,13 +331,13 @@ It's important to note that _how_ hashing works is beyond the scope of this less Inside your `LocalStrategy` function we need to replace the `user.password !== password` expression with the `bcrypt.compare()` function. -```javascript +~~~javascript const match = await bcrypt.compare(password, user.password); if (!match) { // passwords do not match! return done(null, false, { message: "Incorrect password" }) } -``` +~~~ You should now be able to log in using the new user you've created (the one with a hashed password). Unfortunately, users that were saved BEFORE you added bcrypt will no longer work, but that's a small price to pay for security! (and a good reason to include bcrypt from the start on your next project) diff --git a/nodeJS/authentication/project_members_only.md b/nodeJS/authentication/project_members_only.md index 1cce565c541..3a5573ae438 100644 --- a/nodeJS/authentication/project_members_only.md +++ b/nodeJS/authentication/project_members_only.md @@ -15,7 +15,7 @@ This will be a chance for you to use the authentication skills we learned in the 6. When a user is logged in give them a link to "Create a new message" (but only show it if they're logged in!). Create the new-message form. 7. Display all member messages on the home page, but only show the author and date of the messages to other club-members. 8. Add an optional field to the user model called Admin and then add the ability to delete messages, but only allow users who have `admin == true` to see the delete-button and delete messages. You'll need to add a way to actually mark a user as an 'admin' so either add another secret pass-code page, or just put an "is admin" checkbox on the sign-up form. -9. By this point, anyone who comes to the site should be able to see a list of all messages, with the author's name hidden. Users should be able to sign-up and create messages, but ONLY users that are members should be able to see the author and date of each message. Finally, you should have an Admin user that is able to see everything and also has the ability to delete messages. Obviously this is a simple and silly little app, but the things you are practicing (creating and authenticating users and giving users different abilities and permissions) are things that will be _very_ useful to you! +9. By this point, anyone who comes to the site should be able to see a list of all messages, with the author's name hidden. Users should be able to sign-up and create messages, but ONLY users that are members should be able to see the author and date of each message. Finally, you should have an Admin user that is able to see everything and also has the ability to delete messages. Obviously this is a silly little app, but the things you are practicing (creating and authenticating users and giving users different abilities and permissions) are things that will be _very_ useful to you! 10. When you're satisfied with your work, deploy your project on your chosen PaaS [service](https://www.theodinproject.com/lessons/nodejs-deployment) and share it below!
diff --git a/nodeJS/authentication/security_configuration.md b/nodeJS/authentication/security_configuration.md index 43e56b1178d..70631d84657 100644 --- a/nodeJS/authentication/security_configuration.md +++ b/nodeJS/authentication/security_configuration.md @@ -14,7 +14,7 @@ By the end of this lesson, you should be able to do the following: Essentially, in addition to using encryption to secure user passwords we need to make sure that important sensitive information such as our Express sessions secret, our MongoDB url (especially if it includes your username and password!) and any API keys that you might be using stay hidden. Details such as these should never get committed to a git repo or otherwise published. -Hiding secrets is easily accomplished and there are a handful of ways to do it. One of the most common is using an npm package called [dotenv](https://github.com/motdotla/dotenv#readme). Its usage is simple. Simply create a file called `.env` in your project directory and fill it with variables that represent things you need to keep secret using the syntax `[key]=[value]`, for example, `SECRET_KEY="something hard to guess"`. **Important note:** you need to add this file to your `gitignore` so that it does not get committed to git! +Hiding secrets is easily accomplished and there are a handful of ways to do it. One of the most common is using an npm package called [dotenv](https://github.com/motdotla/dotenv#readme). Create a file called `.env` in your project directory and fill it with variables that represent things you need to keep secret using the syntax `[key]=[value]`, for example, `SECRET_KEY="something hard to guess"`. **Important note:** you need to add this file to your `gitignore` so that it does not get committed to git! A more robust option is the package [nconf](https://github.com/indexzero/nconf). It can be used in place of or alongside of dotenv. Basically, it allows you to define configuration files in multiple ways for ultimate flexibility. For example, you could have a config.js file that kept all of your secrets, but also add the ability to override one of those secrets with a command-line argument. diff --git a/nodeJS/express_and_mongoose/deployment.md b/nodeJS/express_and_mongoose/deployment.md index d1f56b4d02e..dfd175aa838 100644 --- a/nodeJS/express_and_mongoose/deployment.md +++ b/nodeJS/express_and_mongoose/deployment.md @@ -95,7 +95,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers ### Fly.io -- Fly.io uses a simple CLI tool for deployment. +- Fly.io uses a convenient CLI tool for deployment. - Pay for what you use with very reasonable rates. Each app should cost around $4 per month. - $20 a month should be enough to host eight apps (including three apps for free). @@ -115,7 +115,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers ### Railway.app -- Railway has a simple deployment process. You link to your project's GitHub repo. +- Railway has a convenient deployment process. You link to your project's GitHub repo. - Pay for what you use model. - $5 a month should be enough to host four applications. @@ -133,7 +133,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers ### Adaptable.io -- Like Railway, has a simple deployment process. You simply link to your project's GitHub repo. +- Like Railway, has a convenient deployment process. You link to your project's GitHub repo. - Free plan does not limit the number of applications you can deploy. - Also has fixed and usage-based payment plans. @@ -154,7 +154,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers ### Render -- Render allows you to deploy using simple "Blueprints", which link to your project's GitHub repo. +- Render allows you to deploy using "Blueprints", which link to your project's GitHub repo. - The free 750-hour allowance is enough to host a few apps without paying anything. However, databases are separate on Render, and the lowest spec databases cost $7 each. This is a good option to use in tandem with MongoDB Atlas. - $21 a month is enough to host three applications as each app's database will cost $7. @@ -174,7 +174,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers ### Heroku -- Heroku has a straightforward deployment process using a combination of a simple and well-documented CLI tool and Git. +- Heroku has a straightforward deployment process using a combination of a well-documented CLI tool and Git. - Heroku is a very mature platform which has been around for over a decade. Any problems you encounter are almost guaranteed to have a solution documented on Stack Overflow or elsewhere on the internet. - The $5 per month eco plan will give you 1000 free hours each month for all your applications. Applications are automatically put to sleep after 30 minutes of inactivity, so the 1000-hour allowance should last the entire month for several of your portfolio projects. - Heroku's lowest-tier Postgresql databases cost $5 per month, effectively costing each application $5 to host. @@ -196,7 +196,7 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers Errors are an inevitable part of the software development process. They especially have a habit of popping up when deploying to a new environment like a hosting provider. When this happens, the key is not to panic and to follow a calm, step-by-step debugging process. -In most cases, you'll be running into errors that thousands of developers have encountered before. These errors are well documented and often have simple solutions you can find with a little bit of Google-fu. +In most cases, you'll be running into errors that thousands of developers have encountered before. These errors are well documented and often have solutions you can find with a little bit of Google-fu. There are two stages of the deployment process where you are most likely to encounter problems. These are during deployment and right after. diff --git a/nodeJS/express_and_mongoose/express_101.md b/nodeJS/express_and_mongoose/express_101.md index 40394eb21c3..69afbb36f4f 100644 --- a/nodeJS/express_and_mongoose/express_101.md +++ b/nodeJS/express_and_mongoose/express_101.md @@ -12,13 +12,13 @@ By the end of this lesson, you should be able to do the following: ### Templating engines -A templating engine is a tool that allows you to insert variables and simple logic into your views. For instance, you could have a header that updates with the actual user's name once they've logged in, something that is not possible with plain HTML. As the lesson mentions, there are several templating languages available for JavaScript. The tutorial uses [Pug (formerly known as Jade)](https://pugjs.org) which has a bit of a learning curve because it looks and feels dramatically different from regular HTML. If you've ever worked with Ruby on Rails you might be more comfortable with [ejs](https://ejs.co), which is _very_ similar to `erb`. +A templating engine is a tool that allows you to insert variables and logic into your views. For instance, you could have a header that updates with the actual user's name once they've logged in, something that is not possible with plain HTML. As the lesson mentions, there are several templating languages available for JavaScript. The tutorial uses [Pug (formerly known as Jade)](https://pugjs.org) which has a bit of a learning curve because it looks and feels dramatically different from regular HTML. If you've ever worked with Ruby on Rails you might be more comfortable with [ejs](https://ejs.co), which is _very_ similar to `erb`. -It's up to you which you choose! If you choose not to use Pug you will still be able to follow the tutorial just fine. Most of the Odin staff prefer ejs over Pug simply because we like working with HTML, but in the end, there is nothing wrong with Pug if you like the look of it or want to learn something new. +It's up to you which you choose! If you choose not to use Pug you will still be able to follow the tutorial just fine. Most of the Odin staff prefer ejs over Pug, because we like working with HTML, but in the end, there is nothing wrong with Pug if you like the look of it or want to learn something new. ### Middleware -This step of the MDN tutorial mentions middleware, but does not clearly define it. Middleware is a complicated word for a simple concept. A middleware is just a plain JavaScript function that Express will call for you between the time it receives a network request and the time it fires off a response (i.e. it's a function that sits in the _middle_). You will eventually be using several of these functions that will run in a specific sequence for every request. +This step of the MDN tutorial mentions middleware, but does not clearly define it. Middleware is a complicated word for a basic concept. A middleware is just a plain JavaScript function that Express will call for you between the time it receives a network request and the time it fires off a response (i.e. it's a function that sits in the _middle_). You will eventually be using several of these functions that will run in a specific sequence for every request. For example, you might have a logger (that prints details of the request to the console), an authenticator (that checks to see if the user is logged in, or otherwise has permission to access whatever they're requesting) and a static-file server (if the user is requesting a static file then it will send it to them). All of these functions will be called in the order you specify every time there's a request on the way to your `app.get("/")` function. @@ -44,11 +44,11 @@ When someone visits your site, their web-browser sends a request to your server. - Check out the documentation for the response object [here!](https://expressjs.com/en/4x/api.html#res) -`next` is a function that you see a little less often, but is _very_ important to the functioning of your app. If you are writing or using some middleware that does not send a response back to the user's client then you _must_ call the `next` function at the end of your middleware function. The next function simply tells express to move to the next middleware in the stack, but if you forget to call it then your app will pause and nothing will happen! +`next` is a function that you see a little less often, but is _very_ important to the functioning of your app. If you are writing or using some middleware that does not send a response back to the user's client then you _must_ call the `next` function at the end of your middleware function. The next function tells express to move to the next middleware in the stack, but if you forget to call it then your app will pause and nothing will happen! #### An example middleware -As a quick example, if you wanted to create a simple logging middleware you could write a function like this: +As a quick example, if you wanted to create a basic logging middleware you could write a function like this: ~~~javascript const myLogger = function(req, res, next) { diff --git a/nodeJS/express_and_mongoose/express_102_crud_and_mvc.md b/nodeJS/express_and_mongoose/express_102_crud_and_mvc.md index 53d15c304fb..7a4a5ea044d 100644 --- a/nodeJS/express_and_mongoose/express_102_crud_and_mvc.md +++ b/nodeJS/express_and_mongoose/express_102_crud_and_mvc.md @@ -15,13 +15,13 @@ By the end of this lesson, you should be able to do the following: ### CRUD -CRUD is a concept that comes up a lot in web development, and it's the type of thing that might show up in interview questions so it's worth taking a little time to make sure you understand what it refers to. Thankfully, it's a relatively simple concept. +CRUD is a concept that comes up a lot in web development, and it's the type of thing that might show up in interview questions so it's worth taking a little time to make sure you understand what it refers to. -CRUD stands for: _Create, Read, Update_ and _Delete_. These are the four basic functions that you will be building into your database driven apps. Put simply, if you are designing a CRUD interface that means that users can expect to be able to do these 4 things to items in the database (providing they have the appropriate permissions of course). +CRUD stands for: _Create, Read, Update_ and _Delete_. These are the four basic functions that you will be building into your database driven apps. If you are designing a CRUD interface that means that users can expect to be able to do these 4 things to items in the database (providing they have the appropriate permissions of course). -In your library example, this simply means that we are going to be building the ability for users to `create` entries (add books, authors or genres to the database), `read` entries (or, retrieve lists of books and other things from the database), `update` entries (edit details of an entry), and `delete` entries (remove them from the database). +In your library example, this means that we are going to be building the ability for users to `create` entries (add books, authors or genres to the database), `read` entries (or, retrieve lists of books and other things from the database), `update` entries (edit details of an entry), and `delete` entries (remove them from the database). -Of course, this is simply a concept and not some sort of rule that must be followed. You may not want to allow users to do all of these actions, or you may want to limit which users can do what at any given time. For example, if you are creating a social networking site, you might only allow users to `read` the profile information of their friends or connections, and you might not want to allow people to `delete` things at all. +Of course, this is a concept and not some sort of rule that must be followed. You may not want to allow users to do all of these actions, or you may want to limit which users can do what at any given time. For example, if you are creating a social networking site, you might only allow users to `read` the profile information of their friends or connections, and you might not want to allow people to `delete` things at all. The CRUD operations roughly correlate to the HTTP methods that you can employ in an express app. This definition can be somewhat flexible, but in general `create` correlates to `POST` (or `app.post()` in an express app), `read` correlates to `GET` (`app.get()`), `update` to `PUT` (`app.put()`) and `delete` to `DELETE` (`app.delete()`) @@ -38,7 +38,7 @@ MVC is another common concept in web development and also something that is like #### MVC example -Without digging into the code prematurely, consider a very simple photo-uploading site. Users can upload and then view photos that are all listed on an index somewhere. In this case, we'll have a model for our photos that would define how our photos are stored in the database (DB). The model might specify that photos should be objects that have a `filename`, a `URL` and a `date-created` field. +Without digging into the code prematurely, consider a very basic photo-uploading site. Users can upload and then view photos that are all listed on an index somewhere. In this case, we'll have a model for our photos that would define how our photos are stored in the database (DB). The model might specify that photos should be objects that have a `filename`, a `URL` and a `date-created` field. We'll need two views, 1) the index, and 2) the display-photo view which will just display a single photo. diff --git a/nodeJS/express_and_mongoose/express_103_routes_and_controllers.md b/nodeJS/express_and_mongoose/express_103_routes_and_controllers.md index 0d5c0789ed1..26adda1243e 100644 --- a/nodeJS/express_and_mongoose/express_103_routes_and_controllers.md +++ b/nodeJS/express_and_mongoose/express_103_routes_and_controllers.md @@ -7,7 +7,7 @@ If you remember from our earlier lessons, the controller is the code that sits b By the end of this lesson, you should be able to do the following: -- Create simple routes. +- Create routes. - Create route-handler callback functions. - Create a catalog route module. - Describe approaches for structuring routes and controllers. diff --git a/nodeJS/express_and_mongoose/introduction_to_express.md b/nodeJS/express_and_mongoose/introduction_to_express.md index 26b09f04d8c..2e50e10283b 100644 --- a/nodeJS/express_and_mongoose/introduction_to_express.md +++ b/nodeJS/express_and_mongoose/introduction_to_express.md @@ -1,5 +1,5 @@ ### Introduction -In the previous lessons, you got up and running with Node. You learned how to serve up a multi-page website and read/write data from files on the server. You probably found that while it wasn't too difficult, the code was verbose and a little complicated. However, you can easily see how complicated and hard to maintain things would get if you decided to start adding more features. [Express](https://expressjs.com/) is a tiny and simple framework that makes the things you did in the previous lessons even quicker and simpler, and does so in a way that makes projects even more easily extensible. +In the previous lessons, you got up and running with Node. You learned how to serve up a multi-page website and read/write data from files on the server. You probably found that while it wasn't too difficult, the code was verbose and a little complicated. However, you can easily see how complicated and hard to maintain things would get if you decided to start adding more features. [Express](https://expressjs.com/) is a tiny framework that makes the things you did in the previous lessons even quicker and simpler, and does so in a way that makes projects even more easily extensible. In this section, we are going to be following the [express tutorial](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs) on MDN. We'll go one lesson at a time, occasionally supplementing with a little deeper explanation or side projects to help you deepen your understanding of the material. There is a *ton* of information there, so be sure to take your time and READ EVERYTHING. The blue "notes" that are scattered throughout the tutorial often link to articles or other tutorials that will definitely improve your understanding of the content. Don't be lazy! @@ -31,7 +31,7 @@ By the end of this lesson, you should be able to do the following: 1. Read the [introductory lesson](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction) on the MDN website. It is long but its main purpose is to show you the various bits and pieces that you'll be learning in the rest of the tutorial. If you want you can code along a bit, but most of the examples aren't really intended for you to follow 100%. *DO* read the entire thing! Some of it will be a review, but that's OK! Follow the links that they give and at least look at them. They are a vital part of this lesson and will often direct you to the relevant portion of the official express docs (which are quite good)! You'll want to be somewhat familiar with them when it comes time to do your own projects. 2. The [second lesson in MDN's Express tutorial](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment#using_npm) walks you through setting up Node and NPM. If you've come this far, you should already have both set up. Still go through the Using NPM and Installing the Express Application Generator sections of this lesson as you'll learn more about installing and getting started with Express. -3. Once you're all set up, take a look at the simple Node site you created in our first project. Rewrite it using express! You should be able to do this with just one app.js file and a few `app.get()`s. +3. Once you're all set up, take a look at the Node site you created in our first project. Rewrite it using express! You should be able to do this with just one app.js file and a few `app.get()`s. diff --git a/nodeJS/express_and_mongoose/project_mini_message_board.md b/nodeJS/express_and_mongoose/project_mini_message_board.md index 49650ccdd69..6f6845293fa 100644 --- a/nodeJS/express_and_mongoose/project_mini_message_board.md +++ b/nodeJS/express_and_mongoose/project_mini_message_board.md @@ -1,5 +1,5 @@ ### Introduction -Let's take a quick break from the main Express tutorial to practice what we've already learned. At this point you should know enough to use Express to make some fun interactive web apps! We're going to create a super simple message board. +Let's take a quick break from the main Express tutorial to practice what we've already learned. At this point you should know enough to use Express to make some fun interactive web apps! We're going to create a message board. ### Assignment diff --git a/nodeJS/final_project/project_odin_book.md b/nodeJS/final_project/project_odin_book.md index bade703f754..15087438de8 100644 --- a/nodeJS/final_project/project_odin_book.md +++ b/nodeJS/final_project/project_odin_book.md @@ -1,51 +1,42 @@ ### Introduction +You've come a long way, congratulations! At this point you should feel comfortable with building new Express applications and using MongoDB to model and store data. This project will require you to put all of that knowledge to the test. It's not going to be easy, but should be well within your capabilities and it will be a _great_ portfolio piece. -You've come a long way, congratulations! At this point, you should feel comfortable with building new Express applications and using MongoDB to model and store data. This project will require you to put all of that knowledge to the test. It's not going to be easy, but it should be well within your capabilities and it will be a _great_ portfolio piece. +You'll be building Facebook. As with our previous lessons, how much effort you want to put into the styling and front-end is up to you. The important stuff is the data and backend. You'll put together the core features of the platform like users, profiles, posts, "liking", "friending", and the news feed. You'll also implement signing in with the real Facebook using our old friend passportJS. -You'll be building a clone of a social media site, such as Facebook, Twitter, Myspace, or Threads. As with our previous lessons, how much effort you want to put into the styling and front end is up to you. The important stuff is the data and backend. You'll put together the core features of the platform like users, profiles, posts, following, and "liking". - -You'll also implement some form of authentication. Ideally, you'll want to use passportJS to support authenticating via the social media site you're cloning, but some sites (such as Facebook), have recently made this process impossible. If this is the case for your site, you can use passportJS to support authenticating via username and password with `passport-local` or via Github with `passport-github2`. - -There will probably be features you haven't been exposed to such as chat, real-time updates, and notifications. You won't be responsible for those unless you're feeling really confident in your skills at this point (It's not _that_ hard... [look here](https://socket.io/) if you want to see what's involved.). +Some features of Facebook are things we haven't been exposed to such as chat, realtime updates of the newsfeed and notifications. You won't be responsible for those unless you're feeling really confident in your skills at this point. (It's not _that_ hard... [look here](https://socket.io/) if you want to see what's involved.) ### Assignment +Build Facebook! You'll build a large portion of the core Facebook user functionality in this project. We won't be worrying about some of the more flashy front-end stuff unless you really want to, but you shouldn't need it to get a nice user experience. -
- -Build a social media site! You'll build a large portion of the core user functionality of your chosen site in this project. You don't have to worry about some of the more flashy front-end stuff unless you want to, but you don't need it to get a nice user experience. - -This project will give you the chance to take a relatively high-level set of requirements and turn it into a functioning website. You'll need to do some of your own research and read the documentation for a few of the modules you'll be using in this project. +This project will give you a chance to take a relatively high level set of requirements and turn it into a functioning website. You'll need to do some of your own research and read the documentation for a few of the modules we'll be using. Keep the following requirements in mind. We'll cover specific steps to get started below this list. -#### Getting started +
-1. Think about what you need to do. It's really helpful to write your plan down on paper or a whiteboard ahead of time! A few hours of thought now will save you days of coding. Try to lay it ALL out. An important part of planning is **scope**. You obviously can't build the entire website (which presumably took a full team of engineers years to produce), so you'll need to identify the site's core functionality and the "nice-to-have" stuff. **Make sure you finish the core functionality BEFORE working on the rest.** If you try to do everything at once, you'll get lost and frustrated. Trust us. Everything takes longer than you expect. -1. Think through the data architecture required to make this work. There are lots of models and the relationship between them is more complicated than anything you've done before. Take some time to plan your approach before diving in. -1. Start your app however you like, using the express-generator or from scratch. -1. Work your way down the list below! Each step will involve a new challenge, but you've got the tools. -1. You can populate data like users and posts with fake data using the [Faker](https://github.com/faker-js/faker) module from npm. To accomplish this create a new JavaScript file named `seeds.js` which imports your Mongoose models and uses the faker module to generate and save a bunch of new users. - -#### Requirements - -The following requirements are a very global list of features your app should have. Because of the open-ended nature of this project, it's possible that not all of them may apply to your chosen site, and that there might be core features of your site that aren't mentioned here. - -1. Users must sign in to see anything except the sign-in page. -1. Users should be able to sign in using your chosen authentication method. -1. Users can send follow requests to other users. -1. Users can create posts (begin with text only). -1. Users can like posts. -1. Users can comment on posts. -1. Posts should always display the post content, author, comments, and likes. -1. There should be an index page for posts, which shows all the recent posts from the current user and users they are following. -1. Users can create a profile with a profile picture. You may be able to get the profile picture when users sign in using Omniauth. If this isn't the case you can use [Gravatar](https://www.gravatar.com/) to generate them -1. A user's profile page should contain their profile information, profile photo, and posts. -1. There should be an index page for users, which shows all users and buttons for sending follow requests to users the user is not already following or have a pending request. -1. Deploy your app to a hosting provider of your choice! +1. Users must sign in to see anything except the sign in page. +2. Users should be able to sign in using their real facebook details. This is fairly easily accomplished using PassportJS, and you should be able to use the knowledge you already have to figure it out [from the documentation](http://www.passportjs.org/docs/facebook/). +3. Users can send friend requests to other users. +4. A user must accept the friend request to become friends. +5. Users can create posts. (begin with text only) +6. Users can like posts. +7. Users can comment on posts. +8. Posts should always display with the post content, author, comments and likes. +9. Treat the Posts index page like the real Facebook's "Timeline" feature -- show all the recent posts from the current user and users they are friends with. +10. Users can create Profile with a photo (you can get this from the real facebook when you sign in using passport) +11. The User Show page contains their profile information, profile photo and posts. +12. The Users Index page lists all users and buttons for sending friend requests to those who are not already friends or who don't already have a pending request. +13. Deploy your app to a host provider of your choice! #### Extra credit -1. Make posts also allow images (either just via a URL or by uploading one.) -2. Allow users to upload and update their profile photo. -3. Create a guest sign-in functionality that allows visitors to bypass the login screen without creating an account or supplying credentials. This is especially useful if you are planning on putting this project on your résumé - most recruiters, hiring managers, etc. will not take the time to create an account. This feature will allow them to look at your hard work without going through a tedious sign-up process. +1. Make posts also allow images (either just via a url, or by uploading one.) +2. Allow Users to upload and update their own profile photo. +3. Create a guest sign-in functionality that allows visitors to bypass the login screen without creating an account or supplying credentials. This is especially useful if you are planning on putting this project on your résumé - most recruiters, hiring managers, etc. will not take the time to create an account. This feature will give them an opportunity to look at your hard work without going through a tedious sign-up process. 4. Make it pretty! +#### Getting started + +1. Think through the data architecture required to make this work. There are lots of models and the relationship between them is more complicated than anything you've done before. How are you going to model a user's list of friends and friend requests? Posts should be able to have likes and comments associated with them, how are you going to model that? Take some time to plan your approach before diving in. +2. Start your app however you like, using the express-generator or from scratch. +3. Work your way down the list above! Each step will involve a new challenge, but you've got the tools. +4. You can populate data like users and posts with fake data using the [Faker](https://github.com/faker-js/faker) module from npm. To accomplish this create a new JavaScript file named `seeds.js` which imports your mongoose models and uses the faker module to generate and save a bunch of new users.
diff --git a/nodeJS/introduction_to_nodeJS/introduction_what_is_nodeJS.md b/nodeJS/introduction_to_nodeJS/introduction_what_is_nodeJS.md index 272921694c8..64f53093313 100644 --- a/nodeJS/introduction_to_nodeJS/introduction_what_is_nodeJS.md +++ b/nodeJS/introduction_to_nodeJS/introduction_what_is_nodeJS.md @@ -11,7 +11,7 @@ By the end of this lesson, you should be able to do the following: - Explain when you wouldn't need a back-end for a project. - Explain the event loop. - Understand the origin of the Node.js runtime. -- Write a simple "hello world" application and run it in the console of your machine. +- Write a basic "hello world" application and run it in the console of your machine. - Understand what Node.js really is. ### What is Node? @@ -22,7 +22,7 @@ The [Node.js website](https://nodejs.org/en/about/) declares: This is a definition that requires a little unpacking. -The important bit to understand right up front is that Node is a "JavaScript runtime". When JavaScript was first created, it was designed to run _in the browser_. This means that it was impossible to use JavaScript to write any kind of program that was not a website. Node brings JavaScript _out_ of browser-land. This allows developers to use JavaScript to accomplish pretty much anything that other popular server-side languages such as Ruby, PHP, C# and Python can do. So, at its most basic level, Node simply allows you to run JavaScript code on a machine such as your local computer or a server without having to go through a web browser. +The important bit to understand right up front is that Node is a "JavaScript runtime". When JavaScript was first created, it was designed to run _in the browser_. This means that it was impossible to use JavaScript to write any kind of program that was not a website. Node brings JavaScript _out_ of browser-land. This allows developers to use JavaScript to accomplish pretty much anything that other popular server-side languages such as Ruby, PHP, C# and Python can do. So, at its most basic level, Node allows you to run JavaScript code on a machine such as your local computer or a server without having to go through a web browser. To facilitate this, Node has some added functionality that is not found in browser-based JavaScript, such as the ability to read and write local files, create http connections and listen to network requests. diff --git a/nodeJS/introduction_to_nodeJS/project_basic_informational_site.md b/nodeJS/introduction_to_nodeJS/project_basic_informational_site.md index 341073cd10e..ab3aacc7394 100644 --- a/nodeJS/introduction_to_nodeJS/project_basic_informational_site.md +++ b/nodeJS/introduction_to_nodeJS/project_basic_informational_site.md @@ -1,4 +1,4 @@ -### A simple Node website! +### A Node website! By now you should know enough to be dangerous. There's *definitely* more to learn but you already know enough about Node to actually make something! So let's do it! You will be creating a very basic informational site that contains 4 pages: index, about, contact-me and 404. Keep in mind that the content of these pages isn't really all that important. So there's no need to spend a lot of time filling them up or trying to make them look pretty. diff --git a/nodeJS/testing_express/testing_database_operations.md b/nodeJS/testing_express/testing_database_operations.md index f6178c02a7f..1f8fbe78227 100644 --- a/nodeJS/testing_express/testing_database_operations.md +++ b/nodeJS/testing_express/testing_database_operations.md @@ -10,7 +10,7 @@ By the end of this lesson, you should be able to do the following: ### But do you even need to test that? -Before diving in, you might want to consider whether or not the database operations you're testing even need to be tested in the first place. If you are simply reading and writing straight from a database using `mongoose` or some other db module, you might not really need to test that code. Mongoose (and presumably all other popular db modules) already has [plenty of tests](https://github.com/Automattic/mongoose/tree/master/test) for all of its actions, so if you are just serving up a JSON API and all you're doing is leveraging functions from another module then those operations are already covered. +Before diving in, you might want to consider whether or not the database operations you're testing even need to be tested in the first place. If you are reading and writing straight from a database using `mongoose` or some other db module, you might not really need to test that code. Mongoose (and presumably all other popular db modules) already has [plenty of tests](https://github.com/Automattic/mongoose/tree/master/test) for all of its actions, so if you are just serving up a JSON API and all you're doing is leveraging functions from another module then those operations are already covered. If your queries are complicated, you might justify adding tests to make sure that you are using them correctly and that the code you have written is doing what you intend it to, and if you are using any of your own code to do some filtering, sorting, or other manipulations of the data you will want to test that as well. In the case of your own code, however, it would be better if you could pull those things out into their own modules, separate from your database operations so you can test them without messing with the database. @@ -20,7 +20,7 @@ There are cases, however, when you are going to want to test things that touch y We're going to use an npm package called `mongodb-memory-server`. You can see the specifics on their [github repo](https://github.com/nodkz/mongodb-memory-server), but basically this package will spin up a fresh in-memory mongoDB server that you can connect to with mongoose, and then use for your testing environment. Since it's creating a fresh DB every time you don't have to worry about trying to keep your data in sync, or polluting your production database. -Setting it up is actually pretty simple, but there are a few things you need to do. First, in your actual app, you need to move your mongo/mongoose setup into its own file as seen in the simple example below. +Setting it up is straightforward, but there are a few things you need to do. First, in your actual app, you need to move your mongo/mongoose setup into its own file as seen in the example below. ~~~javascript //// mongoConfig.js @@ -64,13 +64,13 @@ async function initializeMongoServer() { module.exports = initializeMongoServer; ~~~ -Now, if your tests are set up similarly to the tests in our last project, you can simply call this function in your testing file, and then any operations that work on your mongo database will use this testing one instead of your real one. +Now, if your tests are set up similarly to the tests in our last project, you can call this function in your testing file, and then any operations that work on your mongo database will use this testing one instead of your real one. ### A couple of notes Since you are starting your tests with a fresh database it will probably be useful for you to use a `beforeAll` function in your testing suite to add a couple of items to the database before running tests. -This is also not the only way to set up a testing environment! If you are using nconf, or command-line arguments or anything else to set up your development and production environments, you could easily add a `testing` environment that uses this `mongodb-memory-server`. The [Jest Docs](https://jestjs.io/docs/en/mongodb) demonstrate an alternative (but similar) setup to the simple one we have here. The common element here is that no matter how you accomplish it, our goal is to use this alternative DB when running our tests. +This is also not the only way to set up a testing environment! If you are using nconf, or command-line arguments or anything else to set up your development and production environments, you could easily add a `testing` environment that uses this `mongodb-memory-server`. The [Jest Docs](https://jestjs.io/docs/en/mongodb) demonstrate an alternative (but similar) setup to the one we have here. The common element here is that no matter how you accomplish it, our goal is to use this alternative DB when running our tests. ### Knowledge check This section contains questions for you to check your understanding of this lesson. If you’re having trouble answering the questions below on your own, review the material above to find the answer. diff --git a/nodeJS/testing_express/testing_routes_and_controllers.md b/nodeJS/testing_express/testing_routes_and_controllers.md index 77ae56effab..b659fafd6a8 100644 --- a/nodeJS/testing_express/testing_routes_and_controllers.md +++ b/nodeJS/testing_express/testing_routes_and_controllers.md @@ -18,7 +18,7 @@ By the end of this lesson, you should be able to do or answer the following: The most important, basic requirement for testing something in your code is that it must be in an exported module. This is true for both custom middleware and your routes/controllers, so the very first thing you need to do is separate those things into their own modules, if they aren't already. -In the case of routes, you already know how to do this using Express.Router. Below is a very simple example. +In the case of routes, you already know how to do this using Express.Router. Below is a very basic example. ~~~javascript //// app.js @@ -54,7 +54,7 @@ index.post("/test", (req, res) => { module.exports = index; ~~~ -These two files, `app.js` and `index.js` simply define a couple of routes and then set up and start our express app. For the moment we do _not_ need to test `app.js` because it only contains code that starts and runs an express app! It doesn't include any of our own logic so we don't need to test it. `index.js` however _does_ include some things that we want to test. +These two files, `app.js` and `index.js` define a couple of routes and then set up and start our express app. For the moment we do _not_ need to test `app.js` because it only contains code that starts and runs an express app! It doesn't include any of our own logic so we don't need to test it. `index.js` however _does_ include some things that we want to test. To facilitate actually testing these routes we're going to use a library called [SuperTest](https://github.com/visionmedia/supertest), so go ahead and `npm install supertest --save-dev` and while it's installing take a few minutes to look through the readme on their git repo (linked above). @@ -112,7 +112,7 @@ app.use(express.urlencoded({ extended: false })); app.use("/", index); ~~~ -The tests themselves are relatively simple, thanks to the SuperTest library! Remember that we imported supertest as the function `request` which we use as seen below. We call it on our freshly created express app, pass it our route, and then use it to make sure that the responses match the types and content that we expect. +The tests themselves are relatively straightforward, thanks to the SuperTest library! Remember that we imported supertest as the function `request` which we use as seen below. We call it on our freshly created express app, pass it our route, and then use it to make sure that the responses match the types and content that we expect. Notice the parameter `done` that is passed into the test callback. Most testing libraries use this to signal that the test is complete in the case of asynchronous operations. In this case, SuperTest allows us to pass it into the last `.expect` and calls it for us. Thanks, SuperTest! From 5d5e1af9720c29862991cfc06b37d2774c4617ed Mon Sep 17 00:00:00 2001 From: mclilzee <70924991+Mclilzee@users.noreply.github.com> Date: Mon, 25 Dec 2023 06:20:18 +0100 Subject: [PATCH 002/111] Revert back block changes --- .../authentication/authentication_basics.md | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/nodeJS/authentication/authentication_basics.md b/nodeJS/authentication/authentication_basics.md index 93f35b07c7b..d172b2dfa5c 100644 --- a/nodeJS/authentication/authentication_basics.md +++ b/nodeJS/authentication/authentication_basics.md @@ -28,9 +28,9 @@ We're going to be using another Mongo database, so before we begin log in to you To begin, let's set up a very minimal express app with a single MongoDB model for our users. Create a new directory and use `npm init` to start the package.json file then run the following to install all the dependencies we need: -~~~ +``` npm install express express-session mongoose passport passport-local ejs -~~~ +``` **Mongoose Update**: With the new 7.0.1 version of Mongoose callbacks are no longer supported when querying a database. A promise will be returned instead, meaning that you will now have to use async/await or promises to achieve the same results. If you need a refresher on async/await you can find it in the [Async And Await Lesson](https://www.theodinproject.com/lessons/node-path-javascript-async-and-await) from the JavaScript Course. As you progress through this lesson you will see a blend of using async/await with try/catch blocks as well as other functions that use callbacks, which you've seen as you've progressed through the NodeJS course. You can read more about this change [here](https://mongoosejs.com/docs/migrating_to_7.html#dropped-callback-support). @@ -38,7 +38,7 @@ Next, let's create our `app.js`: **IMPORTANT NOTE**: For the moment we are saving our users with just a plain text password. This is a _really_ bad idea for any real-world project. At the end of this lesson, you will learn how to properly secure these passwords using bcrypt. Don't skip that part. -~~~javascript +```javascript /////// app.js const express = require("express"); @@ -74,13 +74,13 @@ app.use(express.urlencoded({ extended: false })); app.get("/", (req, res) => res.render("index")); app.listen(3000, () => console.log("app listening on port 3000!")); -~~~ +``` Most of this should look familiar to you by now, except for the new imported middleware for express-session and passport. We are not actually going to be using express-session directly, it is a dependency that is used in the background by passport.js. You can take a look at what it does [here](https://github.com/expressjs/session). Our view engine is set up to just look in the main directory, and it's looking for a template called `index.ejs` so go ahead and create that: -~~~html +```html @@ -91,7 +91,7 @@ Our view engine is set up to just look in the main directory, and it's looking f

hello world!

-~~~ +``` ### Creating users @@ -99,7 +99,7 @@ The first thing we need is a sign up form so we can actually create users to aut Create a new template called `sign-up-form`, and a route for `/sign-up` that points to it: -~~~html +```html @@ -117,18 +117,17 @@ Create a new template called `sign-up-form`, and a route for `/sign-up` that poi -~~~ +``` -~~~javascript +```javascript //// app.js app.get("/sign-up", (req, res) => res.render("sign-up-form")); - -~~~ +``` Next, create an `app.post` for the sign up form so that we can add users to our database (remember our notes about sanitation, and using plain text to store passwords...). -~~~javascript +```javascript app.post("/sign-up", async (req, res, next) => { try { const user = new User({ @@ -141,7 +140,7 @@ app.post("/sign-up", async (req, res, next) => { return next(err); }; }); -~~~ +``` Let's reiterate: this is not a particularly safe way to create users in your database... BUT you should now be able to visit `/sign-up`, and submit the form. If all goes well it'll redirect you to the index and you will be able to go see your newly created user inside your database. @@ -154,7 +153,7 @@ Now that we have the ability to put users in our database, let's allow them to l We need to add 3 functions to our app.js file, and then add an app.post for our `/log-in` path. Add them somewhere before the line that initializes passport for us: `app.use(passport.initialize())`. #### Function one : setting up the LocalStrategy -~~~javascript +```javascript passport.use( new LocalStrategy(async (username, password, done) => { try { @@ -171,7 +170,7 @@ passport.use( }; }) ); -~~~ +``` This function is what will be called when we use the `passport.authenticate()` function later. Basically, it takes a username and password, tries to find the user in our DB, and then makes sure that the user's password matches the given password. If all of that works out (there's a user in the DB, and the passwords match) then it authenticates our user and moves on! We will not be calling this function directly, so you won't have to supply the `done` function. This function acts a bit like a middleware and will be called for us when we ask passport to do the authentication later. @@ -179,7 +178,7 @@ This function is what will be called when we use the `passport.authenticate()` f To make sure our user is logged in, and to allow them to _stay_ logged in as they move around our app, passport will use some data to create a cookie which is stored in the user's browser. These next two functions define what bit of information passport is looking for when it creates and then decodes the cookie. The reason they require us to define these functions is so that we can make sure that whatever bit of data it's looking for actually exists in our Database! For our purposes, the functions that are listed in the passport docs will work just fine. -~~~javascript +```javascript passport.serializeUser((user, done) => { done(null, user.id); }); @@ -192,7 +191,7 @@ passport.deserializeUser(async (id, done) => { done(err); }; }); -~~~ +``` Again, we aren't going to be calling these functions on our own, they're used in the background by passport. @@ -200,7 +199,7 @@ Again, we aren't going to be calling these functions on our own, they're used in Let's go ahead and add the login form directly to our index template. The form will look just like our sign-up form, but instead of `POST`ing to `/sign-up` we'll add an `action` to it so that it `POST`s to `/log-in` instead. Add the following to your index template: -~~~html +```html

please log in

@@ -209,11 +208,11 @@ Let's go ahead and add the login form directly to our index template. The form w
-~~~ +``` ... and now for the magical part! Add this route to your app.js file: -~~~javascript +```javascript app.post( "/log-in", passport.authenticate("local", { @@ -221,7 +220,7 @@ app.post( failureRedirect: "/" }) ); -~~~ +``` As you can see, all we have to do is call `passport.authenticate()`. This middleware performs numerous functions behind the scenes. Among other things, it looks at the request body for parameters named `username` and `password` then runs the `LocalStrategy` function that we defined earlier to see if the username and password are in the database. It then creates a session cookie that gets stored in the user's browser, and that we can access in all future requests to see whether or not that user is logged in. It can also redirect you to different routes based on whether the login is a success or a failure. If we had a separate login page we might want to go back to that if the login failed, or we might want to take the user to their user dashboard if the login is successful. Since we're keeping everything in the index we want to go back to "/" no matter what. @@ -231,15 +230,15 @@ The passport middleware checks to see if there is a user logged in (by checking Edit your `app.get("/")` to send the user object to our view like so: -~~~javascript +```javascript app.get("/", (req, res) => { res.render("index", { user: req.user }); }); -~~~ +``` and then edit your view to make use of that object like this: -~~~html +```html @@ -262,13 +261,13 @@ and then edit your view to make use of that object like this: <%}%> -~~~ +``` So, this code checks to see if there is a user defined... if so it offers a welcome message, and if NOT then it shows the login form. Neat! As one last step... let's make that log out link actually work for us. As you can see it's sending us to `/log-out` so all we need to do is add a route for that in our app.js. Conveniently, the passport middleware adds a logout function to the `req` object, so logging out is as easy as this: -~~~javascript +```javascript app.get("/log-out", (req, res, next) => { req.logout((err) => { if (err) { @@ -277,7 +276,7 @@ app.get("/log-out", (req, res, next) => { res.redirect("/"); }); }); -~~~ +``` You should now be able to visit `/sign-up` to create a new user, then log-in using that user's username and password, and then log out by clicking the log out button! @@ -287,12 +286,12 @@ In express, you can set and access various local variables throughout your entir Middleware functions are functions that take the `req` and `res` objects, manipulate them, and pass them on through the rest of the app. -~~~javascript +```javascript app.use((req, res, next) => { res.locals.currentUser = req.user; next(); }); -~~~ +``` If you insert this code somewhere between where you instantiate the passport middleware and before you render your views, you will have access to the `currentUser` variable in all of your views, and you won't have to manually pass it into all of the controllers in which you need it. @@ -310,12 +309,12 @@ Password hashes are the result of passing the user's password through a one-way Edit your `app.post("/sign-up")` to use the bcrypt.hash function which works like this: -~~~javascript +```javascript bcrypt.hash(req.body.password, 10, async (err, hashedPassword) => { // if err, do something // otherwise, store hashedPassword in DB }); -~~~ +``` The second argument is the length of the "salt" to use in the hashing function; salting a password means adding extra random characters to it, the password plus the extra random characters are then fed into the hashing function. Salting is used to make a password hash output unique, even for users who use the same password, and to protect against [rainbow table](https://en.wikipedia.org/wiki/Rainbow_table) and [dictionary](https://en.wikipedia.org/wiki/Dictionary_attack) attacks. @@ -331,13 +330,13 @@ It's important to note that _how_ hashing works is beyond the scope of this less Inside your `LocalStrategy` function we need to replace the `user.password !== password` expression with the `bcrypt.compare()` function. -~~~javascript +```javascript const match = await bcrypt.compare(password, user.password); if (!match) { // passwords do not match! return done(null, false, { message: "Incorrect password" }) } -~~~ +``` You should now be able to log in using the new user you've created (the one with a hashed password). Unfortunately, users that were saved BEFORE you added bcrypt will no longer work, but that's a small price to pay for security! (and a good reason to include bcrypt from the start on your next project) From 9c3dd0bc2bc8328beb71f8abb60dcd63db54303d Mon Sep 17 00:00:00 2001 From: mclilzee <70924991+Mclilzee@users.noreply.github.com> Date: Mon, 25 Dec 2023 06:24:02 +0100 Subject: [PATCH 003/111] Update project to latest iteration --- nodeJS/final_project/project_odin_book.md | 65 +++++++++++++---------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/nodeJS/final_project/project_odin_book.md b/nodeJS/final_project/project_odin_book.md index 15087438de8..bade703f754 100644 --- a/nodeJS/final_project/project_odin_book.md +++ b/nodeJS/final_project/project_odin_book.md @@ -1,42 +1,51 @@ ### Introduction -You've come a long way, congratulations! At this point you should feel comfortable with building new Express applications and using MongoDB to model and store data. This project will require you to put all of that knowledge to the test. It's not going to be easy, but should be well within your capabilities and it will be a _great_ portfolio piece. -You'll be building Facebook. As with our previous lessons, how much effort you want to put into the styling and front-end is up to you. The important stuff is the data and backend. You'll put together the core features of the platform like users, profiles, posts, "liking", "friending", and the news feed. You'll also implement signing in with the real Facebook using our old friend passportJS. +You've come a long way, congratulations! At this point, you should feel comfortable with building new Express applications and using MongoDB to model and store data. This project will require you to put all of that knowledge to the test. It's not going to be easy, but it should be well within your capabilities and it will be a _great_ portfolio piece. -Some features of Facebook are things we haven't been exposed to such as chat, realtime updates of the newsfeed and notifications. You won't be responsible for those unless you're feeling really confident in your skills at this point. (It's not _that_ hard... [look here](https://socket.io/) if you want to see what's involved.) +You'll be building a clone of a social media site, such as Facebook, Twitter, Myspace, or Threads. As with our previous lessons, how much effort you want to put into the styling and front end is up to you. The important stuff is the data and backend. You'll put together the core features of the platform like users, profiles, posts, following, and "liking". -### Assignment -Build Facebook! You'll build a large portion of the core Facebook user functionality in this project. We won't be worrying about some of the more flashy front-end stuff unless you really want to, but you shouldn't need it to get a nice user experience. +You'll also implement some form of authentication. Ideally, you'll want to use passportJS to support authenticating via the social media site you're cloning, but some sites (such as Facebook), have recently made this process impossible. If this is the case for your site, you can use passportJS to support authenticating via username and password with `passport-local` or via Github with `passport-github2`. + +There will probably be features you haven't been exposed to such as chat, real-time updates, and notifications. You won't be responsible for those unless you're feeling really confident in your skills at this point (It's not _that_ hard... [look here](https://socket.io/) if you want to see what's involved.). -This project will give you a chance to take a relatively high level set of requirements and turn it into a functioning website. You'll need to do some of your own research and read the documentation for a few of the modules we'll be using. Keep the following requirements in mind. We'll cover specific steps to get started below this list. +### Assignment
-1. Users must sign in to see anything except the sign in page. -2. Users should be able to sign in using their real facebook details. This is fairly easily accomplished using PassportJS, and you should be able to use the knowledge you already have to figure it out [from the documentation](http://www.passportjs.org/docs/facebook/). -3. Users can send friend requests to other users. -4. A user must accept the friend request to become friends. -5. Users can create posts. (begin with text only) -6. Users can like posts. -7. Users can comment on posts. -8. Posts should always display with the post content, author, comments and likes. -9. Treat the Posts index page like the real Facebook's "Timeline" feature -- show all the recent posts from the current user and users they are friends with. -10. Users can create Profile with a photo (you can get this from the real facebook when you sign in using passport) -11. The User Show page contains their profile information, profile photo and posts. -12. The Users Index page lists all users and buttons for sending friend requests to those who are not already friends or who don't already have a pending request. -13. Deploy your app to a host provider of your choice! +Build a social media site! You'll build a large portion of the core user functionality of your chosen site in this project. You don't have to worry about some of the more flashy front-end stuff unless you want to, but you don't need it to get a nice user experience. + +This project will give you the chance to take a relatively high-level set of requirements and turn it into a functioning website. You'll need to do some of your own research and read the documentation for a few of the modules you'll be using in this project. + +#### Getting started + +1. Think about what you need to do. It's really helpful to write your plan down on paper or a whiteboard ahead of time! A few hours of thought now will save you days of coding. Try to lay it ALL out. An important part of planning is **scope**. You obviously can't build the entire website (which presumably took a full team of engineers years to produce), so you'll need to identify the site's core functionality and the "nice-to-have" stuff. **Make sure you finish the core functionality BEFORE working on the rest.** If you try to do everything at once, you'll get lost and frustrated. Trust us. Everything takes longer than you expect. +1. Think through the data architecture required to make this work. There are lots of models and the relationship between them is more complicated than anything you've done before. Take some time to plan your approach before diving in. +1. Start your app however you like, using the express-generator or from scratch. +1. Work your way down the list below! Each step will involve a new challenge, but you've got the tools. +1. You can populate data like users and posts with fake data using the [Faker](https://github.com/faker-js/faker) module from npm. To accomplish this create a new JavaScript file named `seeds.js` which imports your Mongoose models and uses the faker module to generate and save a bunch of new users. + +#### Requirements + +The following requirements are a very global list of features your app should have. Because of the open-ended nature of this project, it's possible that not all of them may apply to your chosen site, and that there might be core features of your site that aren't mentioned here. + +1. Users must sign in to see anything except the sign-in page. +1. Users should be able to sign in using your chosen authentication method. +1. Users can send follow requests to other users. +1. Users can create posts (begin with text only). +1. Users can like posts. +1. Users can comment on posts. +1. Posts should always display the post content, author, comments, and likes. +1. There should be an index page for posts, which shows all the recent posts from the current user and users they are following. +1. Users can create a profile with a profile picture. You may be able to get the profile picture when users sign in using Omniauth. If this isn't the case you can use [Gravatar](https://www.gravatar.com/) to generate them +1. A user's profile page should contain their profile information, profile photo, and posts. +1. There should be an index page for users, which shows all users and buttons for sending follow requests to users the user is not already following or have a pending request. +1. Deploy your app to a hosting provider of your choice! #### Extra credit -1. Make posts also allow images (either just via a url, or by uploading one.) -2. Allow Users to upload and update their own profile photo. -3. Create a guest sign-in functionality that allows visitors to bypass the login screen without creating an account or supplying credentials. This is especially useful if you are planning on putting this project on your résumé - most recruiters, hiring managers, etc. will not take the time to create an account. This feature will give them an opportunity to look at your hard work without going through a tedious sign-up process. +1. Make posts also allow images (either just via a URL or by uploading one.) +2. Allow users to upload and update their profile photo. +3. Create a guest sign-in functionality that allows visitors to bypass the login screen without creating an account or supplying credentials. This is especially useful if you are planning on putting this project on your résumé - most recruiters, hiring managers, etc. will not take the time to create an account. This feature will allow them to look at your hard work without going through a tedious sign-up process. 4. Make it pretty! -#### Getting started - -1. Think through the data architecture required to make this work. There are lots of models and the relationship between them is more complicated than anything you've done before. How are you going to model a user's list of friends and friend requests? Posts should be able to have likes and comments associated with them, how are you going to model that? Take some time to plan your approach before diving in. -2. Start your app however you like, using the express-generator or from scratch. -3. Work your way down the list above! Each step will involve a new challenge, but you've got the tools. -4. You can populate data like users and posts with fake data using the [Faker](https://github.com/faker-js/faker) module from npm. To accomplish this create a new JavaScript file named `seeds.js` which imports your mongoose models and uses the faker module to generate and save a bunch of new users.
From 65e7007e810a5ae2097c5fb0a5fcbcab82dfd668 Mon Sep 17 00:00:00 2001 From: mclilzee <70924991+Mclilzee@users.noreply.github.com> Date: Mon, 25 Dec 2023 06:37:03 +0100 Subject: [PATCH 004/111] Remove words react --- react/class_components/class_based_components.md | 4 ++-- react/getting_started_with_react/keys_in_react.md | 2 +- react/getting_started_with_react/react_components.md | 10 +++++----- .../getting_started_with_react/rendering_techniques.md | 2 +- react/getting_started_with_react/what_is_jsx.md | 2 +- .../managing_state_with_context_api.md | 4 ++-- react/more_react_concepts/refs_and_memoization.md | 4 ++-- .../project_wheres_waldo_a_photo_tagging_app.md | 2 +- .../react_testing/mocking_callbacks_and_components.md | 6 +++--- .../how_to_deal_with_side_effects.md | 4 ++-- react/states_and_effects/introduction_to_state.md | 4 ++-- react/the_react_ecosystem/fetching_data_in_react.md | 2 +- react/the_react_ecosystem/react_router.md | 4 ++-- .../type_checking_with_proptypes.md | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/react/class_components/class_based_components.md b/react/class_components/class_based_components.md index eb71c10f1b8..b3b7bc7a690 100644 --- a/react/class_components/class_based_components.md +++ b/react/class_components/class_based_components.md @@ -69,7 +69,7 @@ That was a solid chunk of code. Take a while, sip some water and read it a coupl #### The start of a class-based component -Now, let's try to recreate it as a class-based component. The first thing it should have is, _drumroll_, a class! But it cannot be just another class, it will need to have certain properties that qualifies it as a React component. React provides us with all those properties on a class called `Component`, and we can write our components by simply extending the given class, as shown below: +Now, let's try to recreate it as a class-based component. The first thing it should have is, _drumroll_, a class! But it cannot be just another class, it will need to have certain properties that qualifies it as a React component. React provides us with all those properties on a class called `Component`, and we can write our components by extending the given class, as shown below: ~~~jsx import React, { Component } from "react"; @@ -256,7 +256,7 @@ And there we go, we have successfully made our first class-based component, as e
-For the purposes of this assignment, we take the simple class-based component that we built and add additional functionality. There is an interactive example provided at the end to build upon. +For the purposes of this assignment, we take the class-based component that we built and add additional functionality. There is an interactive example provided at the end to build upon. 1. Implement a delete button for each task. The delete button should remove that specific task from the state array, thus deleting the task itself! Styling isn't a priority at this moment, but the button tag should be styled by default. diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md index a7af6c9351c..ff00065445d 100644 --- a/react/getting_started_with_react/keys_in_react.md +++ b/react/getting_started_with_react/keys_in_react.md @@ -11,7 +11,7 @@ By the end of the lesson you should be able to answer the following: ### Why does React need keys? -In the upcoming lessons as you learn more about the internal workings of React, more specifically the rerendering process, you will understand the importance of keys. For now, we will keep it simple. +In the upcoming lessons as you learn more about the internal workings of React, more specifically the rerendering process, you will understand the importance of keys. For now, we will keep it short. In the previous lesson on rendering lists, we used the `.map()` method to iterate over an array of data and return a list of elements. Now imagine, if any of the items in the list were to change, how would React know which item to update? diff --git a/react/getting_started_with_react/react_components.md b/react/getting_started_with_react/react_components.md index da3f717f182..0a60264e9dc 100644 --- a/react/getting_started_with_react/react_components.md +++ b/react/getting_started_with_react/react_components.md @@ -16,18 +16,18 @@ The beauty of React is that it allows you to break a UI (User Interface) down in ![Component Example](https://cdn.statically.io/gh/TheOdinProject/curriculum/91485eec76445d86b29d35894e83324e2967f2fb/react/imgs/00.png) -For example, this simple website could be broken into the following components: +For example, this website could be broken into the following components: - `App`, which represents your main application and will be the parent of all other components. - `Navbar`, which will be the navigation bar. - `MainArticle`, which will be the component that renders your main content. -- `NewsletterForm`, which is a simple form that lets a user input their email to receive the weekly newsletter. +- `NewsletterForm`, which is a form that lets a user input their email to receive the weekly newsletter. Think of these reusable chunks as JavaScript functions which can take some kind of input and return a React element. ### How to create components -To get the feel of working with components, we're going to practice creating functional components. What are functional components? Javascript functions! Is it really that simple? Let's have a look. +To get the feel of working with components, we're going to practice creating functional components. What are functional components? Javascript functions! Let's have a look. ~~~jsx function Greeting() { @@ -35,7 +35,7 @@ function Greeting() { } ~~~ -This might look mostly familiar to you - it's a simple JavaScript function, which returns JSX. Open up the project you were working on, create a new file named `Greeting.jsx`, and in that file write your own handmade functional component. Name it whatever you wish, and have it return whatever JSX you wish. +This might look mostly familiar to you - it's a JavaScript function, which returns JSX. Open up the project you were working on, create a new file named `Greeting.jsx`, and in that file write your own handmade functional component. Name it whatever you wish, and have it return whatever JSX you wish. Are you done? Check the naming of your function! Is it capitalized? Keep this key difference in mind. **React components must be capitalized** or they will not function as expected, which is why we capitalized `Greeting()`. @@ -53,7 +53,7 @@ It's JSX. It looks jarring at first, but soon we'll realize how cool it is. We'l ### Where do components live -So remember how our component is just hanging out in its own dedicated file? This makes it independent from the rest of the codebase! That said, while independence is great, we do want the component to use functionality created elsewhere, and to share itself with other components. How can we do this? `import`ing and `export`ing! For a very long time in React development, it was necessary to `import` React in your JavaScript files that used React components, but since React v17.0 it is no longer required. Let's simply `export` our newly created component so that parent components can use it as a child throughout your project. +So remember how our component is just hanging out in its own dedicated file? This makes it independent from the rest of the codebase! That said, while independence is great, we do want the component to use functionality created elsewhere, and to share itself with other components. How can we do this? `import`ing and `export`ing! For a very long time in React development, it was necessary to `import` React in your JavaScript files that used React components, but since React v17.0 it is no longer required. Let's `export` our newly created component so that parent components can use it as a child throughout your project. ~~~jsx function Greeting() { diff --git a/react/getting_started_with_react/rendering_techniques.md b/react/getting_started_with_react/rendering_techniques.md index 50c111d4167..6bf23f2de38 100644 --- a/react/getting_started_with_react/rendering_techniques.md +++ b/react/getting_started_with_react/rendering_techniques.md @@ -71,7 +71,7 @@ You may be curious as to what the `key` is in our `
  • ` element. We will dive i ### Rendering a list of components in JSX
    -We will use `props` here, and you will learn more about them in a future lesson. For now, you just need to know that `props` are arguments that are passed into components. We will just be writing a simple implementation. +We will use `props` here, and you will learn more about them in a future lesson. For now, you just need to know that `props` are arguments that are passed into components. We will just be writing a short implementation.
    ~~~javascript diff --git a/react/getting_started_with_react/what_is_jsx.md b/react/getting_started_with_react/what_is_jsx.md index 77b802be1db..f42b9010837 100644 --- a/react/getting_started_with_react/what_is_jsx.md +++ b/react/getting_started_with_react/what_is_jsx.md @@ -11,7 +11,7 @@ This section contains a general overview of topics that you will learn in this l ### What is JSX? -JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file. It's not required to use JSX when writing React components, but it does make writing them more simple and concise. +JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file. It's not required to use JSX when writing React components, but it does make writing them more concise. Essentially, JSX is syntactic sugar for the React [createElement](https://react.dev/reference/react/createElement) function. This function creates a React element, which is a plain object, so JSX compiles down to plain JavaScript objects. diff --git a/react/more_react_concepts/managing_state_with_context_api.md b/react/more_react_concepts/managing_state_with_context_api.md index 2c011976ec9..4663cc9854b 100644 --- a/react/more_react_concepts/managing_state_with_context_api.md +++ b/react/more_react_concepts/managing_state_with_context_api.md @@ -109,7 +109,7 @@ So far, what we've done in the `App` component is: - Pass `products` and `addToCart` down to the `ProductDetail` component - Pass `cartItemsCount` down to the `Header` component and the `Links` component that is part of the `Header` -This is a very simple application, but imagine the application grows in size as more features are added, say in the Product Detail Page. There will be a lot more components to nest, and potentially more nested props. What if we have a `Cart` component and a `ProductListing` component? What if we added more functionalities other than just `addToCart`? It can get repetitive and complex because, as we all know, more features equal more complexities. This is especially frequent in component-based frameworks since we're more inclined to create separate reusable components instead of inlining elements, which in turn creates more nesting and passing of props. +This is a very basic application, but imagine the application grows in size as more features are added, say in the Product Detail Page. There will be a lot more components to nest, and potentially more nested props. What if we have a `Cart` component and a `ProductListing` component? What if we added more functionalities other than just `addToCart`? It can get repetitive and complex because, as we all know, more features equal more complexities. This is especially frequent in component-based frameworks since we're more inclined to create separate reusable components instead of inlining elements, which in turn creates more nesting and passing of props. ### Implementing Context API @@ -244,7 +244,7 @@ export default function ProductDetail() { In the `Header` component, we used `useContext()` to access `cartItems` from the `ShopContext`. Similarly, in the `ProductDetail` component, we can use the `products` and `addToCart` function. -With this implementation, we no longer need to pass down props from the `App` component to the `Header` and `ProductDetail` components. The `Header` and `ProductDetail` components can simply access the `cartItems` state and `addToCart` function from the `ShopContext`. +With this implementation, we no longer need to pass down props from the `App` component to the `Header` and `ProductDetail` components. The `Header` and `ProductDetail` components can access the `cartItems` state and `addToCart` function from the `ShopContext`. Overall, the implementation of the Context API has allowed for a more efficient, cleaner, and streamlined way of passing down data across multiple components. By using the `createContext()` function and the `useContext()` hook, we can easily pass down state and functions to child components without the need for prop drilling. It's also more centralized since we're keeping our data in a single location. All of these make our code easier to reason about. diff --git a/react/more_react_concepts/refs_and_memoization.md b/react/more_react_concepts/refs_and_memoization.md index da664de6b43..5c949d30283 100644 --- a/react/more_react_concepts/refs_and_memoization.md +++ b/react/more_react_concepts/refs_and_memoization.md @@ -188,7 +188,7 @@ We can see that the click handler is defined in the `Counter` component, and we' We know that a component renders whenever either state changes or prop changes. Anything inside that is not controlled by React is destroyed and re-executed. Functions, variables, etc. As a result, the function `handleClick` is re-created each time, and the prop `onClick` of the `ButtonComponent` also changes. Alright, so how can `useMemo` help in here? -We already know we can memoize a value using `useMemo`, right? Then we can just cache the function reference and use an empty dependency array so that it won't change. That seems very simple. +We already know we can memoize a value using `useMemo`, right? Then we can just cache the function reference and use an empty dependency array so that it won't change. Let's create a new function and name it `memoizedHandleClick`: @@ -319,4 +319,4 @@ This section contains questions for you to check your understanding of this less This section contains helpful links to related content. It isn’t required, so consider it supplemental. -- The `memo` function is super simple that's why we didn't cover it too much, but if you want to know more about it, especially if you want to create your own logic for the `memo` function go to the [documentation for memo](https://react.dev/reference/react/memo). +- The `memo` function is straightforward that's why we didn't cover it too much, but if you want to know more about it, especially if you want to create your own logic for the `memo` function go to the [documentation for memo](https://react.dev/reference/react/memo). diff --git a/react/react_and_the_backend/project_wheres_waldo_a_photo_tagging_app.md b/react/react_and_the_backend/project_wheres_waldo_a_photo_tagging_app.md index b03f58046ca..b174d55b59b 100644 --- a/react/react_and_the_backend/project_wheres_waldo_a_photo_tagging_app.md +++ b/react/react_and_the_backend/project_wheres_waldo_a_photo_tagging_app.md @@ -2,7 +2,7 @@ This project will finally give you a chance to tie together everything you've learned so far. It's a project with a lot of complexity so take it one step at a time. Working with a backend is pretty straightforward, but you'll be juggling some of the front end functionality too. This is entirely within the realm of the kind of thing you might be asked to build on the job (though of course not exactly). Are you ready? -Have you ever played [Where's Waldo](http://en.wikipedia.org/wiki/Where's_Wally%3F)? If not, that's okay! It's a pretty simple concept: you are presented with a busy and crowded illustration that contains many different people, objects, and places. Your task is to find a particular character named Waldo, who is hidden somewhere in the illustration. +Have you ever played [Where's Waldo](http://en.wikipedia.org/wiki/Where's_Wally%3F)? If not, that's okay! Let us break it down: you are presented with a busy and crowded illustration that contains many different people, objects, and places. Your task is to find a particular character named Waldo, who is hidden somewhere in the illustration. ### Your task diff --git a/react/react_testing/mocking_callbacks_and_components.md b/react/react_testing/mocking_callbacks_and_components.md index cbdcffba4fc..07b79570b40 100644 --- a/react/react_testing/mocking_callbacks_and_components.md +++ b/react/react_testing/mocking_callbacks_and_components.md @@ -16,7 +16,7 @@ If you've been following along with our lessons so far, the concept of mocking h #### Testing callback handlers -Callbacks are ubiquitous. Every avenue of user interaction involves callbacks. Sometimes they're passed in as props to alter state of the parent component. Consider this simple button component: +Callbacks are ubiquitous. Every avenue of user interaction involves callbacks. Sometimes they're passed in as props to alter state of the parent component. Consider this button component: ~~~jsx // CustomButton.jsx @@ -30,7 +30,7 @@ const CustomButton = ({ onClick }) => { export default CustomButton; ~~~ -Nothing fancy. `CustomButton` is a simple component with a prop passed in. We're interested in the `onClick` prop. We have no idea what the function does. We have no idea how the function will affect the application. All we know is it must be called when user clicks the button. Let's test it. +Nothing fancy. `CustomButton` is a component with a prop passed in. We're interested in the `onClick` prop. We have no idea what the function does. We have no idea how the function will affect the application. All we know is it must be called when user clicks the button. Let's test it. Notice how we mock and test the `onClick` function: @@ -86,7 +86,7 @@ You might have come across the concept of mocking modules. In React, when the co ### React testing in the real world -If you're logged in on this ([theodinproject.com](https://theodinproject.com)) website, you've probably come across the project submissions list under every project. Those components were written in React and tested with the React Testing Library. They have since been removed, but they still serve as great examples. This'll be fun. Your task is simple: +If you're logged in on this ([theodinproject.com](https://theodinproject.com)) website, you've probably come across the project submissions list under every project. Those components were written in React and tested with the React Testing Library. They have since been removed, but they still serve as great examples. This'll be fun. Your task is: Read and try to comprehend the [submissions-list.jsx](https://github.com/TheOdinProject/theodinproject/blob/0886578d5b27a967e6bba2b31f212efe284d9413/app/javascript/components/project-submissions/components/submissions-list.jsx) component. It's okay if you don't understand everything. And the good news is that we don't have to understand it all to follow along with this lesson! diff --git a/react/states_and_effects/how_to_deal_with_side_effects.md b/react/states_and_effects/how_to_deal_with_side_effects.md index 18ba22f92da..f41b2ef7489 100644 --- a/react/states_and_effects/how_to_deal_with_side_effects.md +++ b/react/states_and_effects/how_to_deal_with_side_effects.md @@ -109,7 +109,7 @@ useEffect(() => { Oh, it's not going berserk anymore! We still have an issue with the counter updating twice every second though. That can be understood as a [behavior caused by the React StrictMode](https://react.dev/reference/react/StrictMode#strictmode). It is supposed to help us catch bugs, so what is that bug here? -Notice that every time the `useEffect` hook runs, a new `setInterval` is used. When the component is unmounted, `setInterval` is not stopped, it keeps incrementing. This unnecessary behavior can be prevented by simply clearing the interval when the component is unmounted and that is where the third part of our `useEffect` hook comes in - the cleanup function. +Notice that every time the `useEffect` hook runs, a new `setInterval` is used. When the component is unmounted, `setInterval` is not stopped, it keeps incrementing. This unnecessary behavior can be prevented by clearing the interval when the component is unmounted and that is where the third part of our `useEffect` hook comes in - the cleanup function. You can return a function from the callback in the `useEffect` hook, which will be executed each time before the next effect is run, and one final time when the component is unmounted. In this case, let us clean up the interval with a cleanup function. @@ -156,7 +156,7 @@ useEffect( Let us address a few cases where `useEffect` does not need to be used. -* You do not need to use an effect if you are only calculating something based on the state during rendering. For a change in a component, due to a change in the props, you can simply calculate and set it during rendering. +* You do not need to use an effect if you are only calculating something based on the state during rendering. For a change in a component, due to a change in the props, you can calculate and set it during rendering. ~~~jsx import React, { useState } from "react"; diff --git a/react/states_and_effects/introduction_to_state.md b/react/states_and_effects/introduction_to_state.md index c7dd97b8435..93330535192 100644 --- a/react/states_and_effects/introduction_to_state.md +++ b/react/states_and_effects/introduction_to_state.md @@ -1,6 +1,6 @@ ### Introduction -Any exciting application you build is likely to change over the time the user is exploring it. The changes could be as simple as toggling a dropdown menu or as complex as fetching data from an API. React provides primitives to manipulate the state of your apps, more specifically components, to make them dynamic. In this lesson, we will learn how to use state in React. +Any exciting application you build is likely to change over the time the user is exploring it. The changes could be as basic as toggling a dropdown menu or as complex as fetching data from an API. React provides primitives to manipulate the state of your apps, more specifically components, to make them dynamic. In this lesson, we will learn how to use state in React. Read [What is State? by Academind](https://academind.com/tutorials/what-is-state) before we get started. @@ -20,7 +20,7 @@ Let's take a look at how we can use state in our code. -An app that changes its background color based on the clicked button. Pretty simple, right? Take your time reading the code as we'll jump right in. +An app that changes its background color based on the clicked button. Take your time reading the code as we'll jump right in. #### The useState hook diff --git a/react/the_react_ecosystem/fetching_data_in_react.md b/react/the_react_ecosystem/fetching_data_in_react.md index 6ac9e2aeafc..49c2ed76a93 100644 --- a/react/the_react_ecosystem/fetching_data_in_react.md +++ b/react/the_react_ecosystem/fetching_data_in_react.md @@ -198,7 +198,7 @@ const Image = () => { }; ~~~ -If we ever needed to fetch images in different components, instead of rewriting all of that fetching logic we could simply call `useImageURL`. +If we ever needed to fetch images in different components, instead of rewriting all of that fetching logic we could call `useImageURL`. ### Managing multiple fetch requests diff --git a/react/the_react_ecosystem/react_router.md b/react/the_react_ecosystem/react_router.md index 59e821e1ab8..9c05b8a3ab4 100644 --- a/react/the_react_ecosystem/react_router.md +++ b/react/the_react_ecosystem/react_router.md @@ -113,7 +113,7 @@ ReactDOM.createRoot(document.getElementById("root")).render( Once this is done, go ahead and run `npm run dev` and check out both routes: the home route `/` and the profile route `/profile` It works! But what is happening here? 1. We import `createBrowserRouter` and `RouterProvider` from React Router. -2. `createBrowserRouter` is used to create the configuration for a router by simply passing arguments in the form of an array of routes. +2. `createBrowserRouter` is used to create the configuration for a router by passing arguments in the form of an array of routes. 3. The configuration array contains objects with two mandatory keys, the path and the corresponding element to be rendered. 4. This generated configuration is then rendered in, by passing it to the `RouterProvider` component. @@ -422,7 +422,7 @@ const Router = () => { export default Router; ~~~ -Simply add `Router.jsx` component to the `Main.jsx` file: +Add `Router.jsx` component to the `Main.jsx` file: ~~~jsx import React from "react"; diff --git a/react/the_react_ecosystem/type_checking_with_proptypes.md b/react/the_react_ecosystem/type_checking_with_proptypes.md index c9e7f79455d..89d4a805f85 100644 --- a/react/the_react_ecosystem/type_checking_with_proptypes.md +++ b/react/the_react_ecosystem/type_checking_with_proptypes.md @@ -27,7 +27,7 @@ import PropTypes from 'prop-types'; ### Using propTypes -Here is a very basic example of how we would use it in a simple component that renders out a name prop. +Here is a very basic example of how we would use it in a component that renders out a name prop. ~~~javascript import PropTypes from 'prop-types'; From fb08037d9d02e76180aed5c8236d80036bf5bdc7 Mon Sep 17 00:00:00 2001 From: Aanas Aamer <122932921+anasamer056@users.noreply.github.com> Date: Sat, 13 Jan 2024 00:08:34 +0200 Subject: [PATCH 005/111] Add an additional resource to classes.md Add a link to an article that explains composition using real-world examples. This is crucial because examples using animals and vehicles usually aren't enough when explaining concepts related to system design. --- javascript/organizing_your_javascript_code/classes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md index 9e2f2637ae3..219bb77f945 100644 --- a/javascript/organizing_your_javascript_code/classes.md +++ b/javascript/organizing_your_javascript_code/classes.md @@ -62,3 +62,4 @@ This section contains questions for you to check your understanding of this less This section contains helpful links to other content. It isn't required, so consider it supplemental. - [This playlist](https://www.youtube.com/playlist?list=PLtwj5TTsiP7uTKfTQbcmb59mWXosLP_7S) from Stephen Mayeux, explains ES6 Classes and some of their methods with easy to follow examples. +- [This article](https://blog.beezwax.net/composition-over-inheritance-with-javascript-examples) gives real-world examples to illustrate why composition is usually better than inheritance. From 2876e49c07482eb8370b6c17eedc752642b52318 Mon Sep 17 00:00:00 2001 From: Scott Wright <108872957+scottwright-dev@users.noreply.github.com> Date: Thu, 1 Feb 2024 08:38:21 +0000 Subject: [PATCH 006/111] React/Update keys_in_react.md: fix styling inconsistency This commit removes the curly braces {} in line 72 which were wrapped around a code comment in the example to maintain consistency and avoid confusion. --- react/getting_started_with_react/keys_in_react.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md index a7af6c9351c..2029de90a86 100644 --- a/react/getting_started_with_react/keys_in_react.md +++ b/react/getting_started_with_react/keys_in_react.md @@ -69,7 +69,7 @@ const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', function MonthList() { return (
      - {/* here we are using the index as key */} + // here we are using the index as key {months.map((month, index) => (
    • {month}
    • ))}
    ); From cdefc870dda28d4f2b1128286d2985e9cc97aca7 Mon Sep 17 00:00:00 2001 From: Scott Wright <108872957+scottwright-dev@users.noreply.github.com> Date: Thu, 1 Feb 2024 08:52:16 +0000 Subject: [PATCH 007/111] React/Update keys_in_react.md: fix errors for Markdown Lint compliance Fixed markdown linting issues : - Corrected emphasis style from underscore to asterisk. - Added necessary blank lines around lists. - Fixed ordered list item prefix to match expected style. - Removed trailing spaces. - Switched code fence style to backticks from tildes. - Removed extra space after list marker. --- .../keys_in_react.md | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md index 2029de90a86..fc48f02962b 100644 --- a/react/getting_started_with_react/keys_in_react.md +++ b/react/getting_started_with_react/keys_in_react.md @@ -15,9 +15,10 @@ In the upcoming lessons as you learn more about the internal workings of React, In the previous lesson on rendering lists, we used the `.map()` method to iterate over an array of data and return a list of elements. Now imagine, if any of the items in the list were to change, how would React know which item to update? -If the list were to change, one of two things _should_ happen: +If the list were to change, one of two things *should* happen: + 1. we completely re-render the entire list, or: -2. we hunt down the specific items that were changed and only re-render those. +1. we hunt down the specific items that were changed and only re-render those. Assuming we want to hunt down that one specific item that was changed and NOT re-render the entire list. We need something to track that specific item. We can track down a specific item by using a `key`. @@ -28,16 +29,16 @@ As long as `keys` remain consistent and unique, React can handle the DOM effecti ### Using keys
    -We will be using `props` here, and you will learn more about them in the next lesson. For now, you just need to know that `props` are arguments that are passed into components. +We will be using `props` here, and you will learn more about them in the next lesson. For now, you just need to know that `props` are arguments that are passed into components.
    Keys are passed into the component or a DOM element as a prop. You should already be familiar with the syntax. -~~~jsx +```jsx //or
    -~~~ +``` Now that we know the syntax, the next question is: what should be used as a key? Ideally, they should be some identifier that is unique to each item in the list. Most databases assign a unique id to each entry, so you shouldn't have to worry about assigning an id yourself. If you are defining data yourself, it is good practice to assign a unique `id` to each item. You may use the [uuid](https://www.npmjs.com/package/uuid) package to generate a unique id. Let's look at an example: @@ -63,7 +64,7 @@ function TodoList() { Additionally, if you're sure the list will remain unchanged throughout the application's life, you can use the array index as a key. However, this is not recommended since it can lead to confusing bugs if the list changes when items are deleted, inserted, or rearranged. You will learn more about this in the assignment section's linked article. -~~~jsx +```jsx const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; function MonthList() { @@ -74,11 +75,11 @@ function MonthList() { ); } -~~~ +``` Keys are straightforward to use, though there is an anti-pattern you should be aware of. Keys should never be generated on the fly. Using `key={Math.random()}` or `key={uuid()}` _while_ rendering the list defeats the purpose of the list, as now a new `key` will get created for every render of the list. As shown in the above example, `key` should be inferred from the data itself. -~~~jsx +```jsx const todos = [ { task: "mow the yard", id: uuid() }, { task: "Work on Odin Projects", id: uuid() }, @@ -95,7 +96,7 @@ function TodoList() { ); } -~~~ +``` ### Conclusion @@ -125,4 +126,4 @@ This section contains questions for you to check your understanding of this less This section contains helpful links to related content. It isn’t required, so consider it supplemental. -- This article on [React key attribute by Nadia Makarevich](https://www.developerway.com/posts/react-key-attribute) takes an in-depth look into keys. +- This article on [React key attribute by Nadia Makarevich](https://www.developerway.com/posts/react-key-attribute) takes an in-depth look into keys. From 7bcde22cd89c25ea5b180de216b335c05c314c1e Mon Sep 17 00:00:00 2001 From: Scott Wright <108872957+scottwright-dev@users.noreply.github.com> Date: Thu, 1 Feb 2024 08:55:09 +0000 Subject: [PATCH 008/111] React/Update keys_in_react.md: fix additional md linting issues - changes ~~~ to ``` where noted - changes underscore styling with underscores _ to asterisk * --- react/getting_started_with_react/keys_in_react.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md index fc48f02962b..9ebf92e195a 100644 --- a/react/getting_started_with_react/keys_in_react.md +++ b/react/getting_started_with_react/keys_in_react.md @@ -42,7 +42,7 @@ Keys are passed into the component or a DOM element as a prop. You should alread Now that we know the syntax, the next question is: what should be used as a key? Ideally, they should be some identifier that is unique to each item in the list. Most databases assign a unique id to each entry, so you shouldn't have to worry about assigning an id yourself. If you are defining data yourself, it is good practice to assign a unique `id` to each item. You may use the [uuid](https://www.npmjs.com/package/uuid) package to generate a unique id. Let's look at an example: -~~~jsx +```jsx // a list of todos, each todo object has a task and an id const todos = [ { task: "mow the yard", id: uuid() }, @@ -60,7 +60,7 @@ function TodoList() { ); } -~~~ +``` Additionally, if you're sure the list will remain unchanged throughout the application's life, you can use the array index as a key. However, this is not recommended since it can lead to confusing bugs if the list changes when items are deleted, inserted, or rearranged. You will learn more about this in the assignment section's linked article. @@ -77,7 +77,7 @@ function MonthList() { } ``` -Keys are straightforward to use, though there is an anti-pattern you should be aware of. Keys should never be generated on the fly. Using `key={Math.random()}` or `key={uuid()}` _while_ rendering the list defeats the purpose of the list, as now a new `key` will get created for every render of the list. As shown in the above example, `key` should be inferred from the data itself. +Keys are straightforward to use, though there is an anti-pattern you should be aware of. Keys should never be generated on the fly. Using `key={Math.random()}` or `key={uuid()}` *while* rendering the list defeats the purpose of the list, as now a new `key` will get created for every render of the list. As shown in the above example, `key` should be inferred from the data itself. ```jsx const todos = [ From e4d6f32c9cb71172e6905a32c374ec57342b6842 Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 20:49:57 +0530 Subject: [PATCH 009/111] update single spaces --- .../javascript_basics/DOM_manipulation_and_events.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 94ecec76e68..f54a245dc96 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -242,12 +242,12 @@ Copy the example above into files on your own computer. To make it work you'll Add the following elements to the container using ONLY JavaScript and the DOM methods shown above. -1. a `

    ` with red text that says "Hey I'm red!" -2. an `

    ` with blue text that says "I'm a blue h3!" -3. a `
    ` with a black border and pink background color with the following elements inside of it: - 1. another `

    ` that says "I'm in a div" - 2. a `

    ` that says "ME TOO!" - 3. Hint for this one: after creating the `

    ` with createElement, append the `

    ` and `

    ` to it before adding it to the container. +1. a `

    ` with red text that says "Hey I'm red!" +2. an `

    ` with blue text that says "I'm a blue h3!" +3. a `
    ` with a black border and pink background color with the following elements inside of it: + 1. another `

    ` that says "I'm in a div" + 2. a `

    ` that says "ME TOO!" + 3. Hint for this one: after creating the `

    ` with createElement, append the `

    ` and `

    ` to it before adding it to the container. ### Events From 0df33b75259b0ce6174df11b11b65bd7729fd8e3 Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 20:51:01 +0530 Subject: [PATCH 010/111] update nested lists --- .../javascript_basics/DOM_manipulation_and_events.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index f54a245dc96..6b4c2ee604d 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -245,9 +245,9 @@ Add the following elements to the container using ONLY JavaScript and the DOM me 1. a `

    ` with red text that says "Hey I'm red!" 2. an `

    ` with blue text that says "I'm a blue h3!" 3. a `
    ` with a black border and pink background color with the following elements inside of it: - 1. another `

    ` that says "I'm in a div" - 2. a `

    ` that says "ME TOO!" - 3. Hint for this one: after creating the `

    ` with createElement, append the `

    ` and `

    ` to it before adding it to the container. + - another `

    ` that says "I'm in a div" + - a `

    ` that says "ME TOO!" + - Hint for this one: after creating the `

    ` with createElement, append the `

    ` and `

    ` to it before adding it to the container. ### Events From 3800e77babfcd6030ee26d8a7d4fae0c92b9c77c Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 20:51:59 +0530 Subject: [PATCH 011/111] Add Lazy numbering in lists --- foundations/javascript_basics/DOM_manipulation_and_events.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 6b4c2ee604d..02a0173bb5b 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -243,8 +243,8 @@ Copy the example above into files on your own computer. To make it work you'll Add the following elements to the container using ONLY JavaScript and the DOM methods shown above. 1. a `

    ` with red text that says "Hey I'm red!" -2. an `

    ` with blue text that says "I'm a blue h3!" -3. a `
    ` with a black border and pink background color with the following elements inside of it: +1. an `

    ` with blue text that says "I'm a blue h3!" +1. a `
    ` with a black border and pink background color with the following elements inside of it: - another `

    ` that says "I'm in a div" - a `

    ` that says "ME TOO!" - Hint for this one: after creating the `

    ` with createElement, append the `

    ` and `

    ` to it before adding it to the container. From 4bc504cc8d4d58ea7378aa9efc30c13e70d1334b Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 21:03:43 +0530 Subject: [PATCH 012/111] Remove extra spaces --- foundations/javascript_basics/DOM_manipulation_and_events.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 02a0173bb5b..6adb4a1c7c5 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -15,10 +15,8 @@ This section contains a general overview of topics that you will learn in this l ### DOM - Document Object Model - The DOM (or Document Object Model) is a tree-like representation of the contents of a webpage - a tree of "nodes" with different relationships depending on how they're arranged in the HTML document. - ```html

    @@ -26,7 +24,6 @@ The DOM (or Document Object Model) is a tree-like representation of the contents
    ``` - In the above example, the `
    ` is a "child" of `
    ` and a sibling to `
    `. Think of it like a family tree. `
    ` is a **parent**, with its **children** on the next level, each on their own "branch". ### Targeting nodes with selectors From 1bd9ceb302ec89d99940b1ed378461ea1e64d23d Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 21:39:21 +0530 Subject: [PATCH 013/111] resolve md lints --- foundations/javascript_basics/DOM_manipulation_and_events.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 6adb4a1c7c5..02a0173bb5b 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -15,8 +15,10 @@ This section contains a general overview of topics that you will learn in this l ### DOM - Document Object Model + The DOM (or Document Object Model) is a tree-like representation of the contents of a webpage - a tree of "nodes" with different relationships depending on how they're arranged in the HTML document. + ```html
    @@ -24,6 +26,7 @@ The DOM (or Document Object Model) is a tree-like representation of the contents
    ``` + In the above example, the `
    ` is a "child" of `
    ` and a sibling to `
    `. Think of it like a family tree. `
    ` is a **parent**, with its **children** on the next level, each on their own "branch". ### Targeting nodes with selectors From 65d2f7de5bcd9eabb0a9e4b72673ef4fd4ef5daf Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 21:45:06 +0530 Subject: [PATCH 014/111] add blank line after heading --- foundations/javascript_basics/DOM_manipulation_and_events.md | 1 + 1 file changed, 1 insertion(+) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 02a0173bb5b..669c8ac029f 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -442,6 +442,7 @@ This section contains questions for you to check your understanding of this less - [Explain the difference between "capture" and "bubbling".](https://www.youtube.com/watch?v=F1anRyL37lE) ### Additional resources + This section contains helpful links to related content. It isn’t required, so consider it supplemental. - [Eloquent JS - DOM](http://eloquentjavascript.net/13_dom.html) From 1c2371cec02ab41d22e1c1e376fed58abf3f08a8 Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 21:58:36 +0530 Subject: [PATCH 015/111] remove hard tabs --- foundations/javascript_basics/DOM_manipulation_and_events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 669c8ac029f..f4de30d14f7 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -211,7 +211,7 @@ In the JavaScript file, first we get a reference to the `container` div that alr THE TITLE OF YOUR WEBPAGE

    -
    +
    This is the glorious text-content!
    From 33033abc33aa8ae6c3c878183c70c6c91d8644b0 Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 22:02:28 +0530 Subject: [PATCH 016/111] remove blannk lines --- foundations/javascript_basics/DOM_manipulation_and_events.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index f4de30d14f7..147af62317a 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -15,10 +15,8 @@ This section contains a general overview of topics that you will learn in this l ### DOM - Document Object Model - The DOM (or Document Object Model) is a tree-like representation of the contents of a webpage - a tree of "nodes" with different relationships depending on how they're arranged in the HTML document. - ```html
    @@ -26,7 +24,6 @@ The DOM (or Document Object Model) is a tree-like representation of the contents
    ``` - In the above example, the `
    ` is a "child" of `
    ` and a sibling to `
    `. Think of it like a family tree. `
    ` is a **parent**, with its **children** on the next level, each on their own "branch". ### Targeting nodes with selectors From 7e8fce799af45d8ce79e19c62846eecce2e2816b Mon Sep 17 00:00:00 2001 From: adityax4 Date: Sat, 3 Feb 2024 22:30:08 +0530 Subject: [PATCH 017/111] resolve lint error --- foundations/javascript_basics/DOM_manipulation_and_events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 147af62317a..3ae1e30cbe7 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -13,7 +13,7 @@ This section contains a general overview of topics that you will learn in this l - Explain the difference between a "nodelist" and an "array of nodes". - Explain what "bubbling" is and how it works. -### DOM - Document Object Model +### DOM Document Object Model The DOM (or Document Object Model) is a tree-like representation of the contents of a webpage - a tree of "nodes" with different relationships depending on how they're arranged in the HTML document. From f35686fd18f5f37519335754af8a07df807f224d Mon Sep 17 00:00:00 2001 From: adityax4 Date: Tue, 6 Feb 2024 07:54:53 +0530 Subject: [PATCH 018/111] update dom heading --- foundations/javascript_basics/DOM_manipulation_and_events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md index 3ae1e30cbe7..5debef2b747 100644 --- a/foundations/javascript_basics/DOM_manipulation_and_events.md +++ b/foundations/javascript_basics/DOM_manipulation_and_events.md @@ -13,7 +13,7 @@ This section contains a general overview of topics that you will learn in this l - Explain the difference between a "nodelist" and an "array of nodes". - Explain what "bubbling" is and how it works. -### DOM Document Object Model +### Document Object Model The DOM (or Document Object Model) is a tree-like representation of the contents of a webpage - a tree of "nodes" with different relationships depending on how they're arranged in the HTML document. From 3fb64b5114ab35a8a60e60403274f8bc26dfaf73 Mon Sep 17 00:00:00 2001 From: roopxx <127219908+roopxx@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:28:24 +0530 Subject: [PATCH 019/111] Update ordered list as per style guide --- foundations/javascript_basics/revisiting_rock_paper_scissors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundations/javascript_basics/revisiting_rock_paper_scissors.md b/foundations/javascript_basics/revisiting_rock_paper_scissors.md index 0b3f44310d2..a0e94c27d8c 100644 --- a/foundations/javascript_basics/revisiting_rock_paper_scissors.md +++ b/foundations/javascript_basics/revisiting_rock_paper_scissors.md @@ -53,7 +53,7 @@ For example: if you have a bug in a new feature you’re working on that you can 1. Set up a new branch on your previous Rock Paper Scissors repo 1. Since we'll be making a UI for our Rock Paper Scissors game, make a new branch and change to it with the command `git checkout -b rps-ui`. - 2. You are now working in the `rps-ui` branch, locally. However, this branch does not exist in your remote repo yet. If you go to your github repo page, you'll see that you only have 1 branch, which would be `main`. Let's push this new branch to your remote repo with the command `git push origin rps-ui`. Now, you'll see two branches in your GitHub repository! You can select the new branch on GitHub using the dropdown branch selector shown in the screenshot below. + 1. You are now working in the `rps-ui` branch, locally. However, this branch does not exist in your remote repo yet. If you go to your github repo page, you'll see that you only have 1 branch, which would be `main`. Let's push this new branch to your remote repo with the command `git push origin rps-ui`. Now, you'll see two branches in your GitHub repository! You can select the new branch on GitHub using the dropdown branch selector shown in the screenshot below. ![Dropdown menu of branches on GitHub](https://cdn.statically.io/gh/TheOdinProject/curriculum/46c18d8445051e016b1e415fe0227a0fa33cc825/foundations/javascript_basics/revisiting_rock_paper_scissors/imgs/00.png) From fdc72ad118be3d43c0eb3b08b554915e24c9015e Mon Sep 17 00:00:00 2001 From: roopxx <127219908+roopxx@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:05:26 +0530 Subject: [PATCH 020/111] Update codeblock tildes to backticks --- advanced_html_css/accessibility/semantic_html.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/advanced_html_css/accessibility/semantic_html.md b/advanced_html_css/accessibility/semantic_html.md index 33342a22919..187734e8cb8 100644 --- a/advanced_html_css/accessibility/semantic_html.md +++ b/advanced_html_css/accessibility/semantic_html.md @@ -16,27 +16,27 @@ The `
    ` and `` elements, most likely two of the more common elements y Okay, let's look at an actual example to help better understand this whole semantics and context thing. Think of any project you may have completed so far that required a user to click on something: Rock, Paper, Scissors; Calculator; Tic-Tac-Toe. If you used `
    ` or `` elements for any clickable areas, things most likely worked as intended for you. For example, perhaps you had something similar to the HTML below for your Rock, Paper, Scissors UI back in Foundations: -~~~html +```html
    Rock
    Paper
    Scissors
    -~~~ +``` A sighted user would most likely have no trouble playing the game if the elements looked like something to interact with. A screen reader user, however, would have no idea what any of these elements mean. The screen reader would announce the text contents of the element ("Rock", "Paper", or "Scissors"), and the user might think it's just plain text on the page and move on. There's no context to tell the user that they're supposed to, or that they even *can*, interact with these elements. This issue can be easily fixed by using semantic HTML: -~~~html +```html
    -~~~ +``` Because the `