<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: abbyesmith</title>
    <description>The latest articles on DEV Community by abbyesmith (@abbyesmith).</description>
    <link>https://dev.to/abbyesmith</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1031406%2F44479b6b-dbc1-44d9-96ec-45db97be9cc5.jpeg</url>
      <title>DEV Community: abbyesmith</title>
      <link>https://dev.to/abbyesmith</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abbyesmith"/>
    <language>en</language>
    <item>
      <title>Password hashing using Bcrypt in Python</title>
      <dc:creator>abbyesmith</dc:creator>
      <pubDate>Tue, 25 Apr 2023 16:22:29 +0000</pubDate>
      <link>https://dev.to/abbyesmith/password-hashing-using-bcrypt-in-python-2i08</link>
      <guid>https://dev.to/abbyesmith/password-hashing-using-bcrypt-in-python-2i08</guid>
      <description>&lt;p&gt;Hey there tech enthusiasts!&lt;/p&gt;

&lt;p&gt;I am making my way through the Flatiron School bootcamp for software engineering. It is hard to believe that I am now 80% of my way through the course and am approaching my final capstone project. Thus far I have learned JavaScript, React, Python and Flask and just finished my first fill stack project. My final project is going to be a tool for students to use in math class to make graphing homework easier to do on a computer. I know that I want to allow my users to have an account to save their work, so I will be implementing password hashing using bcrypt. This will add a level of security for the users as their passwords will be encoded before saving them to my user table. As many people reuse passwords for different accounts, it’s important that I do my part to ensure their password does not get discovered by a person who would use it for unethical purposes. &lt;/p&gt;

&lt;p&gt;Whether you’re new to programming or a seasoned developer, understanding how to implement bcrypt in Python can be a valuable skill to have in your toolbox. So let’s get started and explore the ins and outs of password hashing with bcrypt in Python!&lt;/p&gt;

&lt;p&gt;Once you have a good understanding of using bcrypt, I strongly encouraging you to add salt to your hashing. Come back in a little bit and I'll add an additional blog post about increasing the security of password storage with salt!&lt;/p&gt;




&lt;p&gt;**Goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add password hashing to SQLAlchemy tables running in Flask (Python)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**Previous Knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating tables in SQLAlchemy (reminders are provided)&lt;/li&gt;
&lt;li&gt;Using PostMan&lt;/li&gt;
&lt;li&gt;Importing libraries&lt;/li&gt;
&lt;li&gt;Setting up the server side of an app&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;*&lt;em&gt;Part 1) Installations:&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Bcrypt is an installation package that you can install via the command line. If you are using Python, use the following command line:&lt;br&gt;
&lt;code&gt;$ pipenv install bcrypt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I am using a Flask framework, so I will install the Flask version of bcryt:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ pipenv install flask-bcrypt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that you have bcrypt in your pipfile, generate your secret key by passing the following in the command line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ python -c 'import os; print(os.urandom(16))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is going to be the key your program uses to encode the password when it is added to the database. Similarly, the secret key will be used to decode the password the next time the user tries to log in. You will need access to this string of random characters soon!&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Part 2) Config File&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
I personally like to have a config.py file in order to cut down on the clutter in my models.py. This is a space to handle all of your imports and metadata boilerplate text. Here is what I have in my config.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_cors import CORS


app = Flask(__name__)
app.secret_key = b'&amp;lt;&amp;lt;This is where your secret key string goes&amp;gt;&amp;gt;'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.json.compact = False

metadata = MetaData(naming_convention={
    "ix": "ix_%(column_0_label)s",
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_`%(constraint_name)s`",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
    })
db = SQLAlchemy(metadata=metadata)

migrate = Migrate(app, db)
db.init_app(app)

bcrypt = Bcrypt(app)

api = Api(app)
CORS(app)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be inserting the secret key into the space indicated.&lt;/p&gt;

&lt;p&gt;Please note that some of these imports are for creating my SQLAlchemy tables. Make the needed adjustments for your project.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Part 3) Models&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
I always like to think about models as what I am modeling my data after. Here is where we are going to form the structure of our tables. For this walk through, I am only going to show a very basic User table with only a username and password. &lt;/p&gt;

&lt;p&gt;At the top of the file, handle your imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sqlalchemy.ext.hybrid import hybrid_property

from config import db, bcrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your User table. You will not be storing the password as the user typed it in. Instead your are storing the encoded version of their password. To acknowledge this in the table, use the column name "_password_hash".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique = True, nullable = False)
    _password_hash = db.Column(db.String)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to start hashing the password. The following boilerplate text is encoding the user's password so your table will store something that doesn't even resemble what was typed in when the user signed up for your site. When the user tries to sign back in, the secret key is used to check if the password input results in the same string of grarbildy goop as what is stored in the table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique = True, nullable = False)
    _password_hash = db.Column(db.String)

    @hybrid_property
    def password_hash(self):
        raise AttributeError('Password hashes may not be viewed.')

    @password_hash.setter
    def password_hash(self, password):
        password_hash = bcrypt.generate_password_hash(
            password.encode('utf-8')
        )
        self._password_hash = password_hash.decode('utf-8')

    def authenticate(self, password):
        return bcrypt.check_password_hash(
            self._password_hash, password.encode('utf-8')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Part 4) App&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The app.py file is where we are adding functionality to our routes. Let's focus on creating a 'POST' for a Signup class and a 'POST' for a Login class. We will be using &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; to check the functionality of the work. &lt;/p&gt;

&lt;p&gt;Begin (as always!) with the needed imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python3

from flask import request, session, make_response
from flask_restful import Resource
from sqlalchemy.exc import IntegrityError


from config import app, db, api
from models import User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you go too much further, hop back to models.py and make your tables. As a reminder, here are the command lines if you are in flask.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# export FLASK_APP=app.py
# export FLASK_RUN_PORT=5555
# flask db init
# flask db revision --autogenerate -m 'Create tables' 
# flask db upgrade 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure your user table is showing up in your database before moving onto the next step.&lt;/p&gt;

&lt;p&gt;Let's create a Signup class that can POST a new user to our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
class Signup(Resource):
    def post(self):

        request_json = request.get_json()

        username = request_json.get('username')
        password = request_json.get('password')

        user = User(
            username = username
        )

        user.password_hash = password

        try:
            db.session.add(user)
            db.session.commit()

            session ['user_id']=user.id

            print (user.to_dict(), 201)

        except IntegrityError:
            print ('nope')

            return {'error': '422 Unprocessable Entity'}, 422

api.add_resource(Signup, '/signup', endpoint='signup')

if __name__ == '__main__':
    app.run(port=5555, debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Part 5) Making the magic happen!&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
You should now be able to go to postman and run &lt;a href="http://127.0.0.1:5555/signup" rel="noopener noreferrer"&gt;http://127.0.0.1:5555/signup&lt;/a&gt; POST. Enter in a username and password to test. If you get a 'null' message after running a POST, then congrats! You did it!! If not, double check your table set up. It's possible a small typo is holding your back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F938sps2vtvc2f5dtm4b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F938sps2vtvc2f5dtm4b1.png" alt="Image description" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To check if you are successful, go over to your table in your database. You should see a new row with username as whatever you entered and a string of nonsense. This is the hashed password.&lt;/p&gt;

&lt;p&gt;To check the functionality of signing in with your hashed password, add a new Login class in app.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Login(Resource):

    def post(self):

        request_json = request.get_json()

        username = request_json.get('username')
        password = request_json.get('password')

        user = User.query.filter(User.username == username).first()

        if user:
            if user.authenticate(password):
                print("authenticate")
                session['user_id'] = user.id
                return user.to_dict(), 200

        return make_response({'error': '401 Unauthorized'},401) 

api.add_resource(Login, '/login', endpoint='login')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Head back to postman. Change the path to &lt;a href="http://127.0.0.1:5555/login" rel="noopener noreferrer"&gt;http://127.0.0.1:5555/login&lt;/a&gt; and enter the same username and password information you used in the signup. You should get back an object with the username and hashed password.&lt;/p&gt;




&lt;p&gt;Way to go! You just helped out your users by making their passwords more secure in your database. If you were able to make it this far, I suggest you look into adding salt to your password hashing method for an extra layer of security. I'll follow up with a blog post on salt shortly!&lt;/p&gt;

</description>
      <category>python</category>
      <category>bcrypt</category>
      <category>password</category>
      <category>security</category>
    </item>
    <item>
      <title>Jazz up a CLI project with color and sound!</title>
      <dc:creator>abbyesmith</dc:creator>
      <pubDate>Sun, 02 Apr 2023 15:50:06 +0000</pubDate>
      <link>https://dev.to/abbyesmith/jazz-up-a-cli-project-with-color-and-sound-moj</link>
      <guid>https://dev.to/abbyesmith/jazz-up-a-cli-project-with-color-and-sound-moj</guid>
      <description>&lt;p&gt;I had a fun time wrapping up phase 3 at Flatiron School in Denver, CO with a CLI project that combined Python with SQLAlchemy. I chose to make a game inspired by Monty Python's Quest for the Holy Grail. If you'd like to check it out and attempt to join King Arthur's Round Table, here is the &lt;a href="https://github.com/abbyesmith/phase3_quest.git"&gt;github repo&lt;/a&gt;. If you try it out, let me know in the comments what you thought!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KGW5aj2w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bplpgt2ipcanb4v0uwq0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KGW5aj2w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bplpgt2ipcanb4v0uwq0.jpeg" alt="poster of Monty Python and the Quest for the Holy Grail" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While you play the game, you may notice that color is used in the command line to make the game more user friendly and sound is used for additional feedback for the user. &lt;/p&gt;

&lt;p&gt;Sound and color were the last add ons to the project before I presented on Friday March 31 and I'm glad I did! Those finishing touches helped my project stand out from some of the others.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;How to add color to Python CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are many different ways to add color into your command line in Python. I decided to try out &lt;a href="https://pypi.org/project/colorama/"&gt;Colorama&lt;/a&gt;. This model will allow the developer to change the foreground color, background color, and weight of the command line text. &lt;/p&gt;

&lt;p&gt;To get started, install Colorama in your pipfile. Open up your Python project's terminal and type in the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ pipenve install coloarama&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check out your pipfile to ensure it was successfully added:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KLCHESfj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiwezfxx2d9lqwo1wuvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KLCHESfj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiwezfxx2d9lqwo1wuvy.png" alt="pipfile with colorama installed" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Note - alternatively, you could use the command &lt;br&gt;
&lt;code&gt;$ pip install colorama&lt;/code&gt; if you do not have a pipfile, this method will make it more difficult for the end user to start up your project because they must manually install colorama)&lt;/p&gt;

&lt;p&gt;Now that you have colorama installed in your Python file, choose a file that you would like to add color. At the top of your file, import colorama.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import colorama&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You must do this on any file that uses colorama.&lt;/p&gt;

&lt;p&gt;Before you get started adding your color, I suggest making a cheat sheet for yourself. Decide when and why color is used. I decided on the following rules for my project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pictures: Magenta Text&lt;/li&gt;
&lt;li&gt;Press Enter: Cyan Text&lt;/li&gt;
&lt;li&gt;Pick a number or text input: Green &amp;amp; Bold Text&lt;/li&gt;
&lt;li&gt;A or B input: Yellow &amp;amp; Bold Text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following colors are available through Colorama:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;black&lt;/li&gt;
&lt;li&gt;red&lt;/li&gt;
&lt;li&gt;green&lt;/li&gt;
&lt;li&gt;yellow&lt;/li&gt;
&lt;li&gt;blue&lt;/li&gt;
&lt;li&gt;magenta&lt;/li&gt;
&lt;li&gt;cyan&lt;/li&gt;
&lt;li&gt;white&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make the text a specific color, use to following in the print or input line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(Fore.MAGENTA + 'the text that should be magenta')&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
To add background colors:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(Back.GREEN 'the text that should be highlighted in green')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To change the weight of the text:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(Style.DIM +'this text will have a lighter weight'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;print(Style.NORMAL +'this text will have a normal weight'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;print(Style.BRIGHT +'this text will have a bold weight'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can combine the commands to give a font color, background and/or weight in one line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(Fore.YELLOW + Back.BLUE + Style.BRIGHT 'this text will be bright yellow with a blue background&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One pesky aspect of Colorama is the style persists until you reset the style. When you are ready for the styling to stop, insert this line into your code:&lt;br&gt;
&lt;code&gt;print(colorama.Style.RESET_ALL)&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;How to add Sound in a Python file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Small sound effects with mp3's added a lot of fun moments in my project and it took relatively little work on my behalf. I used the &lt;a href="https://pypi.org/project/playsound/"&gt;playsound model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started, install playsound so it is added to your pipfile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ pipenv install playsound&lt;/code&gt;&lt;br&gt;
(or &lt;code&gt;$ pip install playsound&lt;/code&gt; if you do not have a pipfile)&lt;/p&gt;

&lt;p&gt;I noticed that some people must also install &lt;a href="https://pypi.org/project/pyobjc/"&gt;pyobjc&lt;/a&gt;. Read the messages when you install playsound to see if you need to do this too.&lt;/p&gt;

&lt;p&gt;At the top of any file that you'd like to use sound, import playsound.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import playsound from playsound&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add whatever mp3 file that you'd like to play when the user is engaging with the command line. I used &lt;a href="https://pixabay.com/sound-effects/search/mp3/"&gt;this site&lt;/a&gt; to find small sound effects when the user answered a question correct or incorrect.&lt;/p&gt;

&lt;p&gt;To insert the sound, decide when you would like the sound effect to play and insert the following line of code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;playsound("path to mp3")&lt;/code&gt;&lt;br&gt;
for example:&lt;br&gt;
&lt;code&gt;playsound("./failure-drum-sound-effect-2-7184.mp3")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a great and quick method if you have a quick sound effect. The program will play through the entire sound clip before it processes the next line.&lt;/p&gt;

&lt;p&gt;If you would like the sound to play in the background while the program continues to run, you'll need to import threading at the top of the file (no need to install anything! Threading is part of the Python package.)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import threading&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I decided to create the variable 'play_sound' to simplify my code later on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;def play_sound():&lt;br&gt;
    playsound('./the-knights-at-camelot-singing-the-entire-knights-of-the-round-table-song.mp3')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Going into the program, I found when I wanted the song to start and called the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sound_thread = threading.Thread(target=play_sound)
sound_thread.start() 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threading method allows the rest of your code to continuously run while the mp3 plays in the background.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Last Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope this quick tutorial helped you spice up your CLI project. I cannot believe that I am already 60% of the way through the Flatiron program - it's been a whirlwind and I have the amazing Flatiron team of David, Stephen, Sam and Yesenia to thank for their support in addition to my amazing cohort! I don't know if I would be successful if it weren't for this gracious community.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>python</category>
      <category>sql</category>
    </item>
    <item>
      <title>How to Create a Practice Quiz using React</title>
      <dc:creator>abbyesmith</dc:creator>
      <pubDate>Sat, 11 Mar 2023 18:35:08 +0000</pubDate>
      <link>https://dev.to/abbyesmith/how-to-create-a-practice-quiz-using-react-j25</link>
      <guid>https://dev.to/abbyesmith/how-to-create-a-practice-quiz-using-react-j25</guid>
      <description>&lt;p&gt;Hey Friends! It's your local teacher turned coder checking in as my bootcamp phase covering React is coming to a close. I'd like to show you how to make a simple practice quiz with automatic scoring on your next project.&lt;/p&gt;

&lt;p&gt;For reference, I created this practice quiz for my phase 2 project at Flatiron School. Here is the &lt;a href="https://github.com/abbyesmith/Algebra-1-Course-Review-Phase-2-Project.git"&gt;link to the project GitHub Repo&lt;/a&gt; and a quick walk through demo of my project. &lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/9dde9e137c4c409eb806a464b76ee535"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;br&gt;
You'll see the practice quiz we are going to walk through in this post at the end of the walk through. If you are thinking about enrolling in a software bootcamp, feel free to drop some questions in the comment box below!

&lt;p&gt;&lt;strong&gt;Part 0 - Create a new create-react-app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Feel free to skip this portion if you plan on adding the code to an already existing project or are comfortable creating a new React app.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html#create-react-app"&gt;these directions&lt;/a&gt; to create a new React app. &lt;/p&gt;

&lt;p&gt;Open your code in your text editor (such as VS Code).&lt;/p&gt;

&lt;p&gt;Remove the existing code in the App.js, App.css, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1 - Render an Example Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To start, let's create the code to have an example problem render on the screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import "./App.css"

function App() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      &amp;lt;h3&amp;gt;Current Correct Answers: 2 out of 3&amp;lt;/h3&amp;gt;
      &amp;lt;h3&amp;gt;Question 4 out of 5&amp;lt;/h3&amp;gt;
      &amp;lt;h2&amp;gt;Who wrote the musical "Hamilton"?&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;button&amp;gt;Lin Manuel Miranda&amp;lt;/button&amp;gt;
        &amp;lt;button&amp;gt;Stephen Sondheim&amp;lt;/button&amp;gt;
        &amp;lt;button&amp;gt;Rodgers and hammerstein&amp;lt;/button&amp;gt;
        &amp;lt;button&amp;gt;James Gunn&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here's a quick snip of what should be rendering on our page:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4CwBXT0P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nz2fkngdzg0gdfs0nnmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4CwBXT0P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nz2fkngdzg0gdfs0nnmp.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2 - Build out a Question Bank&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in using a db.json file, you can build out your question bank there and complete a fetch. &lt;/p&gt;

&lt;p&gt;In order simplify the skills needed, we'll opt to create our question bank as a variable in our App function.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  const questions = [
    {
      questionText: 'Which musical defies gravity?',
      id: 1,
      options: [
        { id: 0, text: 'Annie', isCorrect: false },
        { id: 1, text: 'Book of Mormon', isCorrect: false },
        { id: 2, text: 'Wicked', isCorrect: true },
        { id: 3, text: 'Hade\'s Town', isCorrect: false },
      ],
    },
    {
      questionText: 'Which movie explores the power of the union?',
      id: 2,
      options: [
        { id: 0, text: 'Six', isCorrect: false },
        { id: 1, text: 'Anastasia', isCorrect: false },
        { id: 2, text: 'Newsies', isCorrect: true },
        { id: 3, text: 'The Phantom of the Opera', isCorrect: false },
      ],
    },
    {
      questionText: 'Which band wrote an album intended to be an American musical?',
      id: 3,
      options: [
        { id: 0, text: 'Pink Floyd', isCorrect: false },
        { id: 1, text: 'Simon and Garfunkle', isCorrect: false },
        { id: 2, text: 'Green Day', isCorrect: true },
        { id: 3, text: 'One Direction', isCorrect: false },
      ],
    },
    {
      questionText: 'Who wrote the musical \"Hamilton\"?',
      id: 4,
      options: [
        { id: 0, text: 'Annie', isCorrect: false },
        { id: 1, text: 'Book of Mormon', isCorrect: false },
        { id: 2, text: 'Wicked', isCorrect: true },
        { id: 3, text: 'Hadestown', isCorrect: false },
      ],
    },
    {
      questionText: 'Which musical follows a famous Greek myth?',
      id: 5,
      options: [
        { id: 0, text: 'Hadestown', isCorrect: true },
        { id: 1, text: 'Book of Mormon', isCorrect: false },
        { id: 2, text: 'Wicked', isCorrect: false },
        { id: 3, text: 'Life Of Pi', isCorrect: false },
      ]
    }
  ]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You may add as many questions as you like. Make sure to update the question ID as you go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3 - Map through the Question Bank&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As we map through our data, we are only going to show one question at a time. This means we'll need to useState to set the current question. Create a const as shown in the code block below. Set the initial state to 0 to have the first question generate upon loading the page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, {useState} from 'react';
import "./App.css"

function App() {
  const questions = [
   //Question Bank Here//
      ]
    }
  ]

  const [currentQuestion, setCurrentQuestion] = useState(0);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We'll want to process through our questions when an option choice is clicked. In order to do this, we'll need to create a handleAnswerOptionClick function. We'll keep adding to this function as we build out our code. For now, we'll want to go to the next question as long as there is another question in the bank, as show in the code &lt;code&gt;currentQuestion + 1 &amp;lt; questions.length&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleAnswerOptionClick = () =&amp;gt; {
    if (currentQuestion + 1 &amp;lt; questions.length) {
        setCurrentQuestion (currentQuestion + 1);
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now it's time to make our return dynamic. Replace the question text in the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tags with &lt;code&gt;{questions[currentQuestion].questionText}&lt;/code&gt;. Only the current question will be rendered because &lt;code&gt;[currentQuestion]&lt;/code&gt; is targeting a specific object from our question array. &lt;/p&gt;

&lt;p&gt;In order to show all of the answer choices, map through &lt;code&gt;questions[currentQuestion].options&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To be able to click answer choices and progress to the next question, call our &lt;code&gt;handleAnswerOptionClick&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className = "problem"&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      &amp;lt;h3&amp;gt;Current Correct Answers: 2 out of 3&amp;lt;/h3&amp;gt;
      &amp;lt;h3&amp;gt;Question 4 out of 5&amp;lt;/h3&amp;gt;
      &amp;lt;h2&amp;gt;{questions[currentQuestion].questionText}&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;
        {questions[currentQuestion].options.map((option) =&amp;gt; {
          return(
            &amp;lt;span&amp;gt;
              &amp;lt;button key = {option.id} onClick = {() =&amp;gt; handleAnswerOptionClick()}&amp;gt;
                {option.text}
              &amp;lt;/button&amp;gt;
            &amp;lt;/span&amp;gt;
          )
        })}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check out your React app! You should be able to progress through your questions now. When you reach the end of your questions, you will not be able to progress further.&lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/d769917feffa4c35bd3651aa1ede7b00"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part 4 - Scoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are able to click through your questions at this point, AWESOME JOB! If something is breaking, stop now and go back through your code. Often times a missing bracket or misspelled word can break an entire project. Once your app matches the video from part 3, continue to add a scoring ability to your code. &lt;/p&gt;

&lt;p&gt;First, set some new states. &lt;code&gt;const [id, setId] = useState(0)&lt;/code&gt; will allow us to reference which question # we are on. We'll start at 0 to reference the first object in our question bank array.&lt;/p&gt;

&lt;p&gt;The next new state will be &lt;code&gt;const [score, setScore] = useState(0)&lt;/code&gt;. This will set our initial score as 0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const [id, setId] = useState(0);

  const [score, setScore] = useState(0)

  const [currentQuestion, setCurrentQuestion] = useState(0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's now update the &lt;code&gt;handleAnswerOptionClick&lt;/code&gt; function to add one to the score if the user selects the correct answer. &lt;/p&gt;

&lt;p&gt;We are using the setId state in order to keep track which question number the user is on.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleAnswerOptionClick = (isCorrect) =&amp;gt; {
    if (isCorrect){
      setScore(score + 1)
    }
    if (currentQuestion + 1 &amp;lt; questions.length) {
        setCurrentQuestion (currentQuestion + 1);
        setId (id + 1)
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now move onto the return to make sure the screen renders the correct values. &lt;/p&gt;

&lt;p&gt;Inside the first &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; tags, notice that we are adding &lt;code&gt;{score}&lt;/code&gt; and &lt;code&gt;{id}&lt;/code&gt; to let the user know how many they have answered corrected out of the number attempted. The second set of &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; tags are allowing the user to see their progress through the quiz.&lt;/p&gt;

&lt;p&gt;Moving down, we'll need to pass &lt;code&gt;option.isCorrect&lt;/code&gt; to the &lt;code&gt;handleAnswerOptionClick&lt;/code&gt; function in order for our function to know to read the part of our question bank where the correct answer was identified with &lt;code&gt;isCorrect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className = "problem"&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      &amp;lt;h3&amp;gt;Current Correct Answers: {score} out of {id}&amp;lt;/h3&amp;gt;
      &amp;lt;h3&amp;gt;Question {currentQuestion +1} out of {questions.length}&amp;lt;/h3&amp;gt;
      &amp;lt;h2&amp;gt;{questions[currentQuestion].questionText}&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;
        {questions[currentQuestion].options.map((option) =&amp;gt; {
          return(
            &amp;lt;span&amp;gt;
              &amp;lt;button key = {option.id} onClick = {() =&amp;gt; handleAnswerOptionClick(option.isCorrect)}&amp;gt;
                {option.text}
              &amp;lt;/button&amp;gt;
            &amp;lt;/span&amp;gt;
          )
        })}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Congrats! Users can progress through your quiz and see feedback as they answer the questions. Compare your React app progress with the video below. &lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/24ebac493fb64b02911c0ed9dbe7fd47"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part 5 - Result Screen&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;People love getting immediate feedback on their performance. We are going to add a result screen that shows the user their score on the quiz.&lt;/p&gt;

&lt;p&gt;In order to calculate the grade as a percent, use the line of code &lt;code&gt;let grade = (score / questions.length)*100;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The results page will be called only when the user is at the end of the question bank. We'll control that in our code by using &lt;code&gt;const [showResults, setShowResults] = useState(false)&lt;/code&gt;. &lt;code&gt;showResults&lt;/code&gt; is currently set to false because we do not want the results page to render when the page is loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const [id, setId] = useState(0);

  const [score, setScore] = useState(0)
  let grade = (score / questions.length)*100;

  const [showResults, setShowResults] = useState(false)

  const [currentQuestion, setCurrentQuestion] = useState(0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The handleAnswerOptionClick function is going to get even more powerful! Add an else option at the end of the function to change the value of &lt;code&gt;setShowResults&lt;/code&gt; to allow the result page to render once the user has clicked through the entire quiz.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleAnswerOptionClick = (isCorrect) =&amp;gt; {
    if (isCorrect){
      setScore(score + 1)
    }
    if (currentQuestion + 1 &amp;lt; questions.length) {
        setCurrentQuestion (currentQuestion + 1);
        setId (id + 1)
    } 
    else {
      setShowResults(true)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Move onto the return to build out the results page.&lt;/p&gt;

&lt;p&gt;First, we'll create a ternary statement if &lt;code&gt;showResults&lt;/code&gt; is true, then the result page will render. If &lt;code&gt;showResults&lt;/code&gt; is false, then the questions will render.&lt;/p&gt;

&lt;p&gt;Inside the true aspect of &lt;code&gt;showResults&lt;/code&gt;, create a header titled something similar to "Your Results". &lt;code&gt;{score}&lt;/code&gt; is from our state from earlier. &lt;code&gt;{grade}&lt;/code&gt; references the previous variable that converts the score to a percent.&lt;/p&gt;

&lt;p&gt;Inside the false aspect of &lt;code&gt;showResults&lt;/code&gt;, insert our previously written code for the questions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className = "problem"&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      {showResults ? (
        &amp;lt;div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;h2&amp;gt;Your Results&amp;lt;/h2&amp;gt;
            &amp;lt;h3&amp;gt;Score: {score} out of {questions.length} &amp;lt;/h3&amp;gt;
            &amp;lt;h4&amp;gt;Grade: {grade}%&amp;lt;/h4&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      ) : ( 
        &amp;lt;div&amp;gt;
          &amp;lt;h3&amp;gt;Current Correct Answers: {score} out of {id}&amp;lt;/h3&amp;gt;
          &amp;lt;h3&amp;gt;Question {currentQuestion +1} out of {questions.length}&amp;lt;/h3&amp;gt;
          &amp;lt;h2&amp;gt;{questions[currentQuestion].questionText}&amp;lt;/h2&amp;gt;
          &amp;lt;div&amp;gt;
            {questions[currentQuestion].options.map((option) =&amp;gt; {
              return(
                &amp;lt;span&amp;gt;
                  &amp;lt;button key = {option.id} onClick = {() =&amp;gt; handleAnswerOptionClick(option.isCorrect)}&amp;gt;
                    {option.text}
                  &amp;lt;/button&amp;gt;
                &amp;lt;/span&amp;gt;
              )
            })}
          &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
  )}
  &amp;lt;/div&amp;gt;
  )
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nice! You have a quiz that a user can take once and receive immediate feedback! Make sure your app functions similarly to the video below.&lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/d803918583d8421fabc1b60816a2b110"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part 6 - Allow for Retakes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you want your user to be able to try the quiz more than once without having to reload the page? We can do just that with a few additional lines of code.&lt;/p&gt;

&lt;p&gt;Create a const &lt;code&gt;restartQuiz&lt;/code&gt; to reset our states to 0 or false so the count resets and the user is pushed back to the question set.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const restartQuiz = () =&amp;gt; {
  setScore(0);
  setCurrentQuestion(0);
  setShowResults(false);
  setId(0);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Call &lt;code&gt;restartQuiz&lt;/code&gt; at the end of the results page on a new "Try Again" button.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className = "problem"&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      {showResults ? (
        &amp;lt;div className = "final-results"&amp;gt;
        &amp;lt;div className= "results"&amp;gt;
            &amp;lt;h2 &amp;gt;Your Results&amp;lt;/h2&amp;gt;
            &amp;lt;h3&amp;gt;Score: {score} out of {questions.length} &amp;lt;/h3&amp;gt;
            &amp;lt;h4&amp;gt;Grade: {grade}%&amp;lt;/h4&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;button onClick = {() =&amp;gt; restartQuiz()}&amp;gt;Try Again&amp;lt;/button&amp;gt;

    &amp;lt;/div&amp;gt;
      ) : ( 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;WooHoo!! You have a fully functioning app!! Make sure your app is functioning the video below:&lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/fdaf6f17a5134c60a9abbb5a37ffed56"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part 7 - Add Memes to the End Result&lt;/strong&gt;&lt;br&gt;
If you would like to add a meme that corresponds with the user's score, here's a quick way to make that happen.&lt;/p&gt;

&lt;p&gt;Create an if/else statement with the variable &lt;code&gt;resultImage&lt;/code&gt;. Pick out various memes online or use the ones I have in the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let resultImage
if (grade &amp;gt; 89) {
    resultImage = "https://sayingimages.com/wp-content/uploads/you-did-good-job-meme.jpg"
} else if (grade &amp;gt; 69){
    resultImage = "https://ih1.redbubble.net/image.2500239448.7314/st,small,507x507-pad,600x600,f8f8f8.jpg"
} else if (grade &amp;gt; 49){
    resultImage ="https://cdn.memes.com/up/95499481632781021/i/1633035612375.jpg"
} else {
    resultImage = "https://img.memegenerator.net/instances/54883911.jpg"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call &lt;code&gt;resultImage&lt;/code&gt; in the results portion of your code by adding an image tag with the source set as &lt;code&gt;resultImage&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className = "problem"&amp;gt;
      &amp;lt;h1&amp;gt;Practice Quiz 🤔&amp;lt;/h1&amp;gt;
      {showResults ? (
        &amp;lt;div className = "final-results"&amp;gt;
        &amp;lt;div className= "results"&amp;gt;
            &amp;lt;h2 &amp;gt;Your Results&amp;lt;/h2&amp;gt;
            &amp;lt;h3&amp;gt;Score: {score} out of {questions.length} &amp;lt;/h3&amp;gt;
            &amp;lt;h4&amp;gt;Grade: {grade}%&amp;lt;/h4&amp;gt;
            &amp;lt;img src = {resultImage} alt = "meme"/&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;button onClick = {() =&amp;gt; restartQuiz()}&amp;gt;Try Again&amp;lt;/button&amp;gt;

    &amp;lt;/div&amp;gt;
      ) : ( 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your result page should now render a the meme based on the quiz score. &lt;/p&gt;

&lt;p&gt;This is where I will leave you to use CSS to style your quiz to fit in with your site's theme. &lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>quiz</category>
      <category>usestate</category>
    </item>
    <item>
      <title>Teacher to Software Engineer in 15 Weeks!</title>
      <dc:creator>abbyesmith</dc:creator>
      <pubDate>Wed, 22 Feb 2023 03:29:30 +0000</pubDate>
      <link>https://dev.to/abbyesmith/teacher-to-software-engineer-in-15-weeks-m4e</link>
      <guid>https://dev.to/abbyesmith/teacher-to-software-engineer-in-15-weeks-m4e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0exlhedh2l65xrxbkyn6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0exlhedh2l65xrxbkyn6.jpeg" alt=" " width="800" height="789"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In June 2022 I handed in my letter of resignation to the school that I had taught at for the past 6 years without a clear path on what my future held. The one thing I was certain of was that I did not want to return to the classroom. I decided to step away from a career as a secondary math teacher that had shaped my identity for over a decade and was excited to see what the next step would hold.&lt;/p&gt;

&lt;p&gt;Many people who are not educators, ask why I decided to leave. They often have the assumption that it was something to do with the students. In some conversations, I would lean in and tell horror stories of students gone rogue, especially during the tiktok challenge era that resulted in destroyed bathrooms because that was easier than going into the real reason I decided to leave. In reality, I decided to leave education because my plate was overflowing every day without rest. Even in my sleep, I dreamed of school and woke up in a panic because I was continuously behind on what I wanted to do with and for my students. This is the case with educators around the country and each one is losing more and more of themselves with each passing day.&lt;/p&gt;

&lt;p&gt;Earlier that year, my spouse and I learned that we would not be able to conceive children naturally. We decided to take this heartbreaking news and find the silver lining. We no longer needed to save for the child that we had been trying for since before the Covid-19 Pandemic hit the United States. We had already budgeted for one of us to be a stay at home parent for the first year at minimum. We had our finances set to take on a major life change. That life change just turned out to look different than what we had imagined!&lt;/p&gt;

&lt;p&gt;For the first semester of my freedom from public education, I cheered on my teacher friends and spouse as they began the first day with their students. I turned on my computer and wrote Geometry curriculum for an E-Learning company. I found out that writing curriculum, while interesting, was not what I wanted to do for the remainder of my career. I wanted to take this gift of time to develop a completely new skill set! &lt;/p&gt;

&lt;p&gt;This is when I reflected on the AP Computer Science Principles class I had covered many times in the past year with interest. I also thought back on the technology conference I took my computer repair students to where people in tech gave students a chance to explore different career options. Coding had always intrigued me, but I had never given myself the permission to see myself as a software engineer. I signed up for the pro version of Codecademy for the web development career path. I could lose myself in the lessons and I found so much joy out of creating something out of nothing. As a former math teacher, I realized the skills required to debug a line of code or to process through a logical argument was a skill I used daily in the classroom. While Codecademy was a great way to test the waters, I was ready to commit to a new path as a software engineer!&lt;/p&gt;

&lt;p&gt;As I had experienced first hand the additional hurdles that are in place for online learning, I prioritized finding an in person program that would prepare me to become a software engineer. I found FlatIron School in Denver, signed up and began the mountain of pre-work required to begin the program.&lt;/p&gt;

&lt;p&gt;All of a sudden, the teacher became the student. &lt;/p&gt;

&lt;p&gt;During the first week and a half of the program, I realized what it was like to be a student who doesn’t have the answer. I found myself having to face the reality that I didn’t know everything that was required of me. &lt;/p&gt;

&lt;p&gt;This was terrifying. &lt;/p&gt;

&lt;p&gt;I had earned a full ride scholarship for undergrad and a grant for my masters degree based on my accomplishments as a student. I was the student selected to mentor others. I was always one of the top students. Emphasis on was. &lt;/p&gt;

&lt;p&gt;In my program at Flatiron School, I realized that I was the struggling student when we participated in a pair code activity. I needed to go home and do extra work to keep up. But also, I was the one who was too afraid to ask for help.&lt;/p&gt;

&lt;p&gt;I now realized what my struggling students felt like when they were not able to keep up with their peers and ended up withdrawing from the group. Apart from my brief interaction with the Old English version of Beowolf in Senior year AP English, I had never been a struggling student.  It took a conversation with my instructor, David, to realize that I was not going to be successful on my own and I had to take responsibility for my own learning.&lt;/p&gt;

&lt;p&gt;I started to seek out groups of my peers working on coding labs together and asked to join in. I am trying to work up the courage to admit when I do not understand a key concept early, before it becomes too late. I am trying to add notes to my line of code as a way to deepen my understanding. Not only am I changing my career, but I am also changing my approach to taking care of my own needs.&lt;/p&gt;

&lt;p&gt;Educators are often left to fend for themselves with only other exhausted and overworked teachers to lean on for support. I have come to realize that this has made me self sufficient, but also an island. The pandemic gave time to reflect on many aspects of life, but one lesson that stood out to me is that &lt;strong&gt;we are stronger together&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;I strive to use my time during the remainder of the software engineer bootcamp to get out of my old habits and reach out for help early and often. For the remainder of my time as a student at Flatiron School, I am setting a daily goal to reach out to my instructor at least once each day, and to work with a peer at least once each day. Breaking habits can be hard, but not impossible!&lt;/p&gt;

</description>
      <category>vibecoding</category>
    </item>
  </channel>
</rss>
