React State Management with the Context API

Component-level state is the state within an individual component. It is only available to that component and only affects that component. We can use hooks such as useState to control component-level state.

But what if you want a piece of state to be available to multiple different components or all of your components? This is what we call application-level state.

Application-level state is the state that is available to the entire application. In order to implement this type of state, we need to implement more complex solutions.

One solution would be to “lift up” the state. This involved moving the piece of state to your App component, the root component which holds all of the other components. While this is a bit simpler to implement than other solutions, the problem with it is that you are giving the App component state that it doesn’t directly need and you will have to pass down the state to each component in a very long-winded way. This is called prop-drilling.

Instead, we can use the Context API as a more dynamic and versatile solution. Here’s an example of how it would be used:

Context File

import React, { useState, createContext } from 'react';

export const MyContext = createContext();

export const MyProvider = props => {
   const [property, setProperty] = useState('Initial state of property');

   return (
      <MyContext.Provider value={[property, setProperty]}>
         {props.children}
      </MyContext.Provider>

App File

import React from 'react';
import { MyProvider } from './MyContext';

function App() {
   return (
      <MyProvider>
         <div>
            <MyComponent />
            Other Components...
         </div>
      </MyProvider>
   );
}

Component File

import React, { useState, useContext } from 'react';
import { MyContext } from './MyContext';

const MyComponent = () => {
   const [property, setProperty] = useContext(MyContext);

   return (
      <h1>{property}</h1>
   );
};

export default MyComponent;

The downside to the Context API is every time we update the code in our Context, all the components that use the context have to re-render.

The benefits are that it’s more simple than Redux and doesn’t require any third-party libraries.

MySQL in the Terminal

The default path to MySQL on Mac is /usr/local/mysql/bin.

If you type mysql --version, you may get an error saying “command not found.” This is because you don’t have the MySQL command in your path.

To solve this, you can do one of two things:

# This will add MySQL to your current session (will be lost when you close Terminal)
export PATH=${PATH}:/usr/local/mysql/bin
# Permanantly
echo 'export PATH="/usr/local/mysql/bin:$PATH"' >> ~/.bash_profile

Copy and paste whichever command you prefer into Terminal. Close & reopen your Terminal window after you run the command.

Now, if you type mysql --verison, it should show you your version of MySQL.

Log in and use MySQL in the Terminal using this command: mysql -u root -p. It will ask for your password; make sure you use your MySQL password, not your system password

Ctrl + L to clear the prompt

Show users:

SELECT User, Host FROM mysql.user;

Create user: When you create a new database for a new application, you will probably want to have a specific user for that database rather than using the root user

CREATE USER 'someuser'@'localhost' IDENTIFIED BY 'somepassword';

Leave the MySQL Terminal

quit

Insert A Record Into MySQL Database from Server POST Request (Node + MySQL)

There are 2 ways to insert data from the req.body of a route:

Method #1

router.post('/', (req, res) => {
    const userInfo = req.body;

    const sql = "INSERT INTO users SET ?";

    mysqlConnection.query(sql, userInfo, (err, rows, fields) => {
        if (!err) {
            res.send(rows);
        } else {
            console.log(err.message);
            res.send(err);
        }
    })
});

Method #2

router.post('/', (req, res) => {
    const { name, username } = req.body;

    const sql = "INSERT INTO users (name, username) VALUES ('${name}', '${username}')";

    mysqlConnection.query(sql, (err, rows, fields) => {
        if (!err) {
            res.send(rows);
        } else {
            console.log(err.message);
            res.send(err);
        }
    })
});

Code Formatting with Prettier in VS Code

No one likes messy code, but no one likes painstakingly formatting their code as they write it either. The Prettier plugin on VS Code takes care of that for us.

To install it, navigate to the fifth panel on the VS Code sidebar

Type “Prettier” into the search bar and it should be the first option in the list

It’s installed now, but we’re not done. We have to do some set up to get Prettier working in our files.

Navigate to the Settings at the bottom left corner of the screen.

Type “format on save” into the search bar. Change this property to true. This will make it so that whenever we save a file that we’re working on, Prettier will automatically format it for us.

Type “prettier” into the search bar. You will see a list of around 20 properties that dictate the formatting rules Prettier will follow. Change these settings to your preference.

For example, you can change “prettier.singleQuote” to true if you don’t want to deal with some of your code using double quotes and other parts using single quotes.

Save your new settings, close VS Code, and you’re good to go!

Hiding API Keys in Environment Variables and Pushing Code to Github

To accomplish this, we will be using an npm package called dotenv.

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env

  1. Install the dotenv package
npm i dotenv

2. Require dotenv in the server file

require('dotenv').config();

3. Create a new file in your project called .env

4. In the .env file, paste all of your API keys

API_KEY=4423b234y329324b32

5. Access the API key with process.env

const api_key = process.env.API_KEY;

6. Create a .gitignore file and add the .env file to it

The code in the .gitignore file:

.env

7. Upload to Github!

It’s recommended to include something that will help others understand what to do with .env variables whether that be using the README, .env_sample, etc.

Error: MySQL Workbench Hangs When Connecting to Database

Problem: Whenever I click on my Local Connection to get access to my MySQL Database, Workbench attempts to open it then freezes.

Solution: It’s not ideal, but I have to delete the Local Instance and create a new one. It works for me after that.

Right-click on the Local Instance and select “Delete Connection.” Then Press the “+” button next to “MySQL Connections.”

Fill in the Connection Name (any name you want) and Password (the password we created earlier during the MySQL installation). Then, test the connection using the Test Connection button at the bottom. If the connection is successful, press OK.

Node.js MySQL Tutorial

This tutorial assumes you have Node.js, MySQL, and MySQL Workbench installed

  1. Create a new Node application

Create the package.json and install the necessary dependencies

cd project-folder
npm init
npm i express express-handlebars mysql

2. Create a new MySQL Database

Create a new Schema. I will call mine Practice

3. Set up your server file

Quickly set up your server file and initiate your MySQL Connection in order to make sure the connection is running successfully before we go any further.

const express = require("express");
const mysql = require("mysql");

const app = express();

app.use(express.urlencoded({ extended: false }));
app.use(express.json({ extended: true }));

const mysqlConnection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "password",
    database: "Practice",
    multipleStatements: true
})

mysqlConnection.connect((err) => {
    if (!err) {
        console.log("Connection Successful");
    } else {
        console.log("Connection Failed");
        console.log(err.message);
    }
})

app.listen(3000);

Run your Node app

node index.js OR nodemon index.js

If your Terminal logs “Connection Successful”, move to Step 4

4. Move MySQL Connection to separate file

This is not required; it’s simply for organization’s sake

At the same level as the server file, make a new file. I’ll call mine connection.js

This will be the contents of the file:

const mysql = require("mysql");

const mysqlConnection = mysql.createConnection({
   host: "localhost",
   user: "root",
   password: "josh-mysql",
   database: "Practice",
   multipleStatements: true
});

mysqlConnection.connect((err) => {
   if (!err) {
      console.log("Connection Successful");
   } else {
      console.log(err.message);
   }
});

module.exports = mysqlConnection;

In the server file, import the MySQL connection from the connection.js file:

const mysqlConnection = require("./connection");

5. Create a table in the database

I’m going to open up my Practice Schema and find the Tables. Then, I’m going to right-click on Tables and create a new Table by clicking “Create Table.” Give your table a name and whatever properties you would like. Then, press Apply.

My projects table have properties of id and name

6. Create a route and query the database

In my server file, I’m going to handle GET requests to the root route. When a user requests the root route, I will query the MySQL database for all of the items in our projects table and send back the items in the response.

app.get("/", function(req, res){
   mysqlConnection.query("SELECT * from projects", (err, rows, fields) => {
      if (!err) {
          res.send(rows);
      } else {
         console.log(err);
      }
   })
});

Let’s test out our route. Run your server with node index.js, open up Postman and send a GET request to the root route.

Since we haven’t created any records into our projects table, this request should return an empty array.

That’s it! You’ve set up a basic Node server with a MySQL database.

What is Data Science?

Data Mining is the application of specific algorithms for extracting patterns from data

For decades, data mining was being done with Statistics. In the 1990s, when Computer Science was getting exponentially popular, people started doing Data Mining with Computer Science.

Data Mining + Computer Science = Data Science

Data Science is an interdisciplinary field that uses scientific methods, processes, algorithms and systems to extract insights from data.

Fun fact: IBM pioneered the first relational database

There are three main career specializations within the Data Science field:

  1. Data Engineer
  2. Data Scientist
  3. Machine Learning Expert

The Data Engineer comes first in the process of creating value from data. It is the Data Engineer’s job to collect and store data. Then comes the Data Scientist; it is his/her job to take this data, clean it and explore/visualize it (w/ statistics, graphs, charts, etc.). After that, the Machine Learning Expert can apply intelligent algorithms to the data in order to extract insights from it.

Data Science Workflow

Data Scientist’s take a systematic approach to answering questions with data. It usually follows this pattern:

  1. Formulate Question
    • clear; scientifically testable
  2. Gather Data
  3. Clean Data
    • remove missing, incomplete, inaccurate data
  4. Explore & Visualize
    • helps to better understand the data
  5. Train Algorithm
  6. Evaluate
    • did the results answer our question?

Setting up MySQL on Mac

MySQL is a relational database management system. It is one of the most popular RDMS’s out there today.

It is open-source, but it’s also backed by Oracle so you can use it without any commercial license or you can purchase premium services & support from Oracle

Installing MySQL on macOS

Go to this link. You should see a page with the title MySQL Community Server. Choose whichever version you want to download; you can just download the first version in the list if you’re not sure.

Open the .dmg Installer and go through the setup screens in the modal popup. When it asks for a password for your root, choose a fairly robust password and write it down somewhere because you’ll be using it in any MySQL applications.

To check if the installation was successful, go to your computer’s System Preferences and if you see the MySQL icon in one of the rows, your installation was successful.

Double click the MySQL icon to open a modal window in which you can start or stop your MySQL Server.

Installing MySQL Workbench

MySQL Workbench is a GUI tool that lets you manage your MySQL databases much more simply.

Go to this link and select MySQL Workbench from the list of Community Downloads.

There will only be one Installer option so press Download, then choose “No thanks, just start my download” and the download will start.

Open the .dmg Installer and drag MySQL workbench into the Applications folder. That’s it, you’ve set it up!

When you open MySQL Workbench, you may see this message (“MySQL Workbench could not detect any MySQL server running. This means that MySQL is not installed or is not running”).

Since we know we installed MySQL earlier, this unwanted message is displaying because MySQL server is not running on our computer.

To start the server on your computer, go to your computer’s System Preferences, double click the MySQL icon, and you should see this page.

Press “Start MySQL Server” to start your server. Close MySQL Workbench and reopen the application. Now, you should see:

This is what we want to see. Press on this button. *If you press it and you get an error, delete the connection and create a new one.

How to Create a New Connection

Press the “+” button.

Fill in the Connection Name (any name you want) and Password (the password we created earlier during the MySQL installation). Then, test the connection using the Test Connection button at the bottom. If the connection is successful, press OK.

When you press on the Local Connection now, it should work.

Errors Connecting to MySQL in Node

ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

In MySQL Workbench, open a blank Query page and execute these commands (Query > Execute (All or Selection)):

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;

This is what it will look like in Workbench:

ER_ACCESS_DENIED_ERROR: Access denied for user ‘root’@’localhost’ (using password: YES)

In the part of your Node application where you define the connection to the MySQL database, set password to an empty string:

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: ''
});

After you re-run your server, the error will go away, but you may be left with a new error– the error below:

ER_MUST_CHANGE_PASSWORD_LOGIN: Your password has expired. To log in you must change it using a client that supports expired passwords.

Execute the following query in MYSQL Workbench (change new-password to your own new password):

ALTER USER `root`@`localhost` IDENTIFIED BY 'new-password',
       `root`@`localhost` PASSWORD EXPIRE NEVER;
flush privileges;