How to Manage State by Using the React Context API

When I work on large-scale applications, I use Redux for state management. However, when it comes to building smaller applications and smaller personal projects, Redux can feel cumbersome. So, what’s the best light-weight solution for state management of these smaller applications? React hooks work really well for smaller applications, but sometimes you need to share state between components, and passing that state through components via props can get a little clunky. That’s where React Context comes to the rescue.

By utilizing the React Context API, you can avoid prop drilling. It also helps keep your components cleaner and simpler.

Let’s walk through what this would look like if we’re adding React Context to an application. First, I like to organize my context within a contexts folder within the src directory. Then I create a context file where all the global state will live. For this example, let’s call the file ItemContext.js:

import { createContext, useState } from "react";
import PropTypes from "prop-types";
const ItemContext = createContext();
const ItemProvider = ({ children }) => {
  const [items, setItems] = useState([]);
  const addItem = (item) => {
    const index = items[items.length - 1].id + 1;
    item.id = index;
    const updatedItems = [...items, item];
    setItems(updatedItems);
  };
  const editItem = (id, item) => {
    const index = items.findIndex((e) => e.id === id);
    const updatedItems = [...items];
    updatedItems[index] = item;
    setItems(updatedItems);
  };
  const removeItem = (id) => {
    const updatedItems = [...items];
    setItems(updatedItems.filter((item) => item.id !== id));
  };
  const context = {
    addItem,
    editItem,
    items,
    removeItem,
  };
  return <ItemContext.Provider value={context}>{children}</ItemContext.Provider>;
};
export { ItemContext, ItemProvider };
ItemProvider.propTypes = {
  children: PropTypes.object,
};

Next, within the src directory, if you don’t already have a hooks directory, create one where we’ll add a new hook file, useItemContext.js:

import { useContext } from "react";
import { ItemContext } from "../contexts/ItemContext";
const useItemContext = () => {
  return useContext(ItemContext);
};
export default useItemContext;

This file probably looks fairly small, but it will help us cut back on copying and pasting the same lines of code when we want to reference this global state. Now, when we want to access the global state or update the state via various components, we can do so by importing the context hook:

import useItemContext from "../hooks/useItemContext";
const ExampleComponent = () => {
  const { addItem, editItem, removeItem } = useItemContext();
  const handleAdd = (item) => {
    addItem(item);
  };
  const handleRemove = () => {
    removeItem(item.id);
  };
  const handleSave = (item) => {
    editItem(item.id, item);
  };
  return (
    {Add your presentation logic here}
  );
};
export default ExampleComponent;

Lessons Learned from a Mass Tech Layoff

This year was the first time I was ever laid off from a company, and I figured I’d share my lessons learned from the experience. Maybe you’ll find them helpful if you ever find yourself in a similar situation or if you’re going through the same thing at the moment.

Lessons I learned from getting laid off from my Senior Software Engineering role:

  1. Instead of diving into job hunting immediately, take some time to rest beforehand. I dove into job hunting immediately, although I was still feeling devastated from being laid off from a company that had been a dream job for me. I was processing my grief over losing a job while also feeling extremely exhausted from staying up late studying for technicals and waking up early for my scheduled interviews. This made it difficult to perform at my best during those interviews.

  2. Don’t apply to too many places at once. Right after getting laid off, I panic-applied to a lot of companies. As a result, I had several companies responding to me at the same time to set up interviews. My calendar was crammed with interviews – recruiter calls, technicals, and take home assessments. I ended up feeling extremely overwhelmed and was spread too thin, and ultimately bombed too many interviews because I overextended myself. If I could go back and do things differently, I would have been more selective at the beginning of my job hunt. That way I wouldn’t have been so exhausted in the beginning.

  3. Filter the unsolicited advice you’re getting from others and focus on what makes sense for you and your situation. I had a lot of friends/family give me their take on how I should approach the job hunting process. At first, I was trying to listen to too many people at once, and as a result, I was not only overwhelmed from everything that was going on in my life, but I was also overwhelmed from all the advice I was getting. What works for one person may not work for you, and that’s totally okay. Do what makes sense for you and makes the job hunting process manageable for you. For me, this meant cutting back on the interviews I was scheduling each week. I know that people mean well when they give you unsolicited advice, but no one truly knows what you’re going through better than you do, and ultimately you know better about what works for you.

  4. Prioritize your mental health. Losing my source of income and my health insurance, processing the emotions from getting laid off, as well as dealing with the rejection that comes with the job hunting process, took a toll on my mental health. At first I was interviewing too much and not giving myself enough space to continue to pursue my hobbies or doing things that make me happy. Later, I realized I had to cut back on interviews so I could protect my happiness and mental health, and make time to do things that would bring me joy during this difficult time.

  5. Have a strategic approach for the companies/roles that you apply to. At first, I didn’t have a strategy other than to apply to any role that fit my skill set at companies I was familiar with/really liked. Later, I realized the interview process was very important to me since I’m primarily self-taught, and live coding/whiteboarding interviews have always been tough for me. I ended up applying to companies that had tech screens that catered to my strengths while spending some of my free time working on LeetCode problems and studying CS so that I could move back to live coding/whiteboarding interviews in the future.

  6. You can negotiate your severance. I had no idea you could negotiate your severance, so I just signed off on what was offered to me. If I could go back, I would have tried to negotiate, although the layoff my company did was one where there probably wasn’t much room for negotiation since so many people were laid off.

  7. Listen to your gut. When you no longer have a job, it’s easy to feel desperate and feel like you should accept the first offer you get. If you’re financially able to hold off on doing that, I’d recommend waiting until you get an offer that excites you. I had a couple potential offers in the beginning of my search, but I wasn’t excited about them at all. And I think that’s definitely a red flag – you don’t want to start working for a company if off the bat you have some resentment about the offer.

  8. Network and use social media to your advantage. I was able to get a lot of leads on possible job opportunities by reaching out to people who used to work at my previous companies. I was also getting a lot of help from strangers reaching out to me when I posted about getting laid off on LinkedIn.

Hopefully this is helpful for anyone else going through something similar. If you recently found a new job, congrats! If you’re still on the search for something new, good luck and hang in there!

How I Made a Twitterbot with Node.js

The other day, I decided to make a Twitterbot to help streamline my marketing efforts for my art brand. I wanted to make a bot that would retweet tweets from a different user, selected from a list of users. I wanted the bot to also run once a day.

For my project, I used the following:

  • Node.js
  • twit – Twitter API client for Node.js
  • Heroku – platform for deployed applications

Creating an Application with Twitter

To get started, I used the Twitter application form to register my application. The process is pretty straight forward, and once it was completed, I was able to grab the necessary consumer_key, consumer_secret, access_token, and access_token_secret.

Building the Bot

To get started with Node.js, I created a new project directory. Then I ran npm init.

I ran the following commands to ensure I had the right packages to build the application:

npm install --save dotenv http twit

Next, I created the environment variables. I created a .env file in the directory, where I added in my project keys:

CONSUMER_KEY="add_it_here"
CONSUMER_SECRET="add_it_here"
ACCESS_TOKEN="add_it_here"
ACCESS_TOKEN_SECRET="add_it_here"

In my index.js file, I connected the .env variables to the application:

require("dotenv").config();
const config = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET
};

Then I added logic so the bot would retweet tweets from a list of users or retweet tweets tied to specific hashtags. First I set variables to use twit and to control the number of retweets the bot would make when the code was executed:

const twit = require("twit");
const Twitter = new twit(config);
const MAX_RT_COUNT = 1;

I found the Twitter ids for several users that I wanted to the bot to retweet. I used their ids instead of their screen names, in case a user decided to change their screen name. In order to keep track of who was who, I stored details about each user in a comment:

const USERS = [
  "15057943", // moma
  "14803372", // saam
  "5225991", // tate
  "22009731", // design museum
  "81783051", // artsy
  "17896874", // itsnicethat
  "158865339", // fastcodesign
  "21661279", // creative review
  "16336998", // print magazine
  "17623957", // design observer
  "418597196", // creativebloq
  "15446126", // design milk
  "18201801", // interior design
  "19038849" // how design
];

I made a function that would filter through the list of users, so that each day of the week, a different user would get a retweet from the bot:

const getUserOfTheDay = () => {
  let date = new Date();
  let dayOfMonth = date.getDate();
  let pickUserIndex = dayOfMonth % USERS.length;
  return USERS[pickUserIndex];
};

Next, I created the logic for retweeting tweets tied to different hashtags. I ultimately decided not to deploy this functionality, but I wanted to keep it around in case it’s useful in the future:

let retweetTags = async function() {
  try {
    const { data } = await Twitter.get("search/tweets", {
      q: "#art, #painting",
      result_type: "mixed",
      lang: "en"
    });

    const statuses = data.statuses.slice(0, MAX_RT_COUNT);
    // loop through the first n returned tweets
    for (const status of statuses) {
      // the post action
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

// retweetTags();

Lastly, I added the code for retweeting tweets from my list of users:

let retweetUsers = async function() {
  try {
    const { data } = await Twitter.get("users/show", {
      user_id: getUserOfTheDay()
    });

    const status = data.status;
    // make sure tweet isn't in reply to another user
    if (status.in_reply_to_status_id == null) {
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

To run the bot locally, I added retweetUsers(); to the file, then ran node index.js in the terminal.

Deploying the App to Heroku

Once I had my app up and running locally, I wanted to deploy it somewhere so it could run automatically. I did this by deploying it to Heroku.

I added a Procfile to the project, and added the line worker: node index.js to the file. Then I created a new Heroku project by running heroku create twitterbot-retweet. Next, I had to define the environment variables in Heroku by running heroku set:config key_name="key_value" in the terminal.

By accessing the Heroku dashboard online, I had to toggle on the worker for the bot (it was located under the “Dyno formation” section).

After deploying the bot, I realized I wanted the bot to run once every day, so I looked into options for how I could wake the application up once a day in order to execute the code. I ended up going with the simple setInterval method.

If your curious about how all the code looks, or want to see an up-to-date version of the project, you can find it on GitHub.

How I Found a Remote Job

Finding a remote job ended up requiring quite a bit of persistence on my part. Before looking for a fully remote job, I had no idea how competitive remote jobs are. What really helped me land quite a few interviews, some of which were with some pretty large companies, was the fact that I have a pretty big online presence. I not only blog on my web developer portfolio site, but I have created an online presence for my artwork. I was competing with a lot of applicants who have more of a Computer Science background, but I think my online presence helped me stick out.

When I was applying to various roles, I kept combing the following job boards/online services:

  • FlexJobs – this is a paid service, although if you’re unhappy with your subscription in any way, they’ll give you a refund
  • Hiring without Whiteboards – this repo includes companies that have remote roles
  • Remote.co
  • We Work Remotely (this one was my favorite, and is actually where I found the company where I landed a remote role)

It also helped that I have had previous experience working remotely for companies and contracting work, so I’m familiar with the various ways of communicating with colleagues in different cities. Many companies with remote employees are interested in if applicants have had previous experience working remotely, so they know if candidates are able to work remotely on their own. After all, remote work isn’t for everyone, and it’s a matter of trying it out to determine if it’s the type of environment you can thrive in.

Two Years Since GA: A Review of my Coding Bootcamp Experience

It’s hard to believe, but exactly two years ago I took leave from my company to attend General Assembly’s Web Development Immersive (WDI) program. Previously, I had hopped around with different web-related roles, learning coding on my own and picking up on best practices along the way. Since I didn’t have a background in Computer Science, I really wanted to get a better foundation, thus I decided to attend a coding bootcamp.

What was Great about General Assembly

WDI was an amazing experience in many ways. I’d have a say that I really appreciated the following:

  • Meeting a wonderful group of aspiring developers that came from all different backgrounds.
  • Being a part of an amazing community, and feeling much more confident about my abilities as a coder.
  • Having hands-on experience by building applications for labs, as well as creating four different projects (although I have to say I wasn’t proud of one of my projects, so it was more like having three different polished projects).
  • Getting introduced to new frameworks like Angular JS and popular libraries like React JS.
  • Having many “ah ha!” moments, where things would click and I realized that I had a much better understanding for different programming concepts and patterns.
  • Getting the tools I needed to become a better learner.
  • Feeling passionate again about technology and web development – prior to joining their program, I was feeling burned out at work. WDI helped motivate and inspire me again.

What Could Have Been Better

  • I wasn’t thrilled with their Outcomes programming. I enjoyed the panels they had and an interview workshop, but overall I felt like too much time was spent away from working on projects while focusing on things like resumes and cover letters (which I felt like I already knew enough about). I’d say it would have been better if there was less mandatory Outcomes programming, with the option to participate in some of their activities.
  • Technical interview prep would have been nice. We barely scratched the surface when it came to technical interviews, and I didn’t feel at all prepared for technical interviews once I started interviewing for developer jobs.
  • Better communication about how difficult it is to land a dev job earlier in your career. It felt like they kept saying it was easy if you worked hard enough, which is a bit vague and not terribly helpful.
  • More focus on frameworks and libraries. I had a different background than a lot of my peers in the program, since I had a bit of experience with programming. The first few weeks felt a lot like review for me, and once I started working with new frameworks and libraries, it seemed like we rushed over the material. I would have preferred less basics for HTML, CSS, JavaScript, and Ruby, and more detailed work with React JS.

Other Thoughts

Overall, I thought General Assembly’s WDI was an amazing experience, and I definitely don’t regret it. Was it perfect? No, but it helped me in just the right ways. I enjoyed the people I met and the community that I was a part of. I kept referring to it as being like camp for grownups. It was a lot of fun, was incredibly challenging at times, but was well worth it.

Can I Host Multiple Sites with GitHub?

The other day I was looking into hosting websites on GitHub Pages, and I found myself wondering if it’s possible to host multiple custom domains for a single GitHub account. I came to the conclusion that it isn’t possible. You can use one custom domain per account, and that custom domain can effect different types of repositories within your account. For instance, if I used megancoyle.com for my custom domain, it would be the new URL used to access my GitHub site page that was previously accessed via megancoyle.github.io. Then project pages would no longer have the URL megancoyle.github.io/hangman, but would use megancoyle.com/hangman instead.

So if you want to keep your other repos more separate from your personal page, you may want to rethink how you use a custom domain. Or you’ll possibly want to think about how you’d like to brand your different repositories.

Here are a couple of articles that can help you with linking your domains to GitHub Pages:

View at Medium.com

Linking Namecheap to GitHub Pages

Hangman

Project Details:

Single-page JavaScript app coded in Vanilla JavaScript and utilizes HTML5’s canvas element. I also had a lot of fun using a RegEx for updating the letters whenever the user guesses the correct letter in the word.

View the project

Technology Used:

  • Vanilla JavaScript
  • HTML5 Canvas

hangman application

How to Make Requests to Yelp’s API v3 (Fusion)

I recently worked on updating an app I made a couple of years ago, that was using Yelp’s API. I was running into some issues deploying the older version of the app to Heroku, so I decided to update the API it was using to the latest version for Yelp, v3.

As I’m writing this, I found that the Yelp API documentation was a little confusing. The older API required a consumer key, consumer secret, token, and token secret. The Yelp Fusion API only requires an Authorization parameter.

Authentication for the Yelp API is outlined here, although I had to do a bit of fiddling around until I was able to successfully make an API GET request. Here’s what Postman looked like once I was able to make a successful call (click the image to see a larger view):

Something I wasn’t aware of from the APIs I’ve worked with, is that the Headers required a Content-Type with the value application/json and an Authorization with a value that started with the word Bearer, a space, and then the API key I had received from Yelp. So the value looked something like Bearer 203498lksjsdlkfej9if

If you’re curious about how I wrote the code for my application, you can take a look at my github repo for the app, What am I Even Doing?

New Design for Nextgov

Earlier this year, I joined Atlantic Media as a Web Developer. Last week, I got to be part of the first major launch while working for the company – relaunching Nextgov with a redesigned website.

Nextgov redesign

I got to work with Python and Django, and learned a lot about the company’s deployment process. It was interesting joining a team when they were in the middle of a project – I had to try to make sense of unfamiliar code, as well as do my best to catch up to speed with the project. It was fun working on the different apps integrated within their website, and I enjoyed learning more about the back-end development process with Django.

A Brief Overview of Ruby

Iterators

  • Iterators make it easier to write code
5.times do
  puts “hello”
end
  • Integers/floats: times, unto, down to, step
  • Range: each, step
  • String: each, each_line, each_byte
  • Array: each, each_index, each_with_index
  • Hash: each, each_key, each_value, each_pair

Methods

  • Values are passed in when they are called, and they are sometimes abbreviated as args
  • Operators are also methods in ruby
  • Syntactic sugar refers to simplifying the code
  • Syntactic vinegar – not so tasty code
  • Methods are all lowercase with underscores

Classes

  • Classes use camel case (they always start with a capital letter): SomeName
  • Classes group the code into discreet, well-categorized areas
  • Can define methods inside a class
class Animal
  def make_noise
    “Moo!”
  end
end
animal.make_noise
  returns “Moo!”
  • make_noise object is created from the class and then we can tell it to do things
  • Objects let us organize code into well-categorized areas
  • Allow complex behaviors using simple statements
  • Instance: an object created from a class
animal = Animal.new
puts animal.make_noice
  • Animal.new is an instance which is an object
  • .new is a class method

Instance Variables

  • Instance variables start with an @ symbol – @variable
  • Instance variables are used within the instance of a class
  • Allow us to keep track of attributes
  • Never have access to instance variables from outside the instant
  • We can access methods within instance, so need to use methods to get instance variable
  • Setter methods – sets a variable equal to value
  • Getter methods – getting that value back

Attribute Methods

  • Methods that we put into classes – takes symbols and turns them into methods
    • attr_reader
    • attr_writer
    • attr_accessor (creates a reader and a writer method)

Additional Terms

  • Instantiated = creating a new instance
  • Class Method – a method that can be called on a class even without an instance of the class
  • Class attributes – store values that apply to the class generally stored in a class variable @@variable
  • Instance variables are only inside the instance
  • Inheritance – inherits the methods and attributes of another class
  • Can only inherit from one super class
  • Modules are wrappers around classes