Coding Journal

Jordan Vidrine

Daily Coding Journal

A Self-taught coder from the Cajun Prairie in rural Louisiana, currently working as a designer for Discourse.

I am always trying to better myself, and do so through learning new skills, trying out new routines, traveling, and pouring energy into hobbies. Since 2014, I have been recording, editing, and producing my own music under the name Skies Speak.

October 22nd

I started off the day coding a solution to a ‘Dad Jokes API’ React site. Here is the following code that I came up with to build the site, rendering 10 ‘Dad Jokes’ from an API, and storing them in local storage for retrieval after a user closes the page.


// JokeApp Class
import React, {Component} from 'react';
import './JokeApp.css';
import Jokes from './Jokes';
import axios from 'axios';

class JokeApp extends Component {
  static defaultProps = {
    numJokesToGet: 10
  }
  constructor(props) {
    super(props)
    this.state = {
      jokes: []
    }
    this.vote = this.vote.bind(this)
    this.getJokes = this.getJokes.bind(this)
    this.getNewJokes = this.newJokes.bind(this)
  }

  componentDidMount() {
    this.getJokes()
  }

  async getJokes() {
    let jokes = this.load()
    while (jokes.length < this.props.numJokesToGet) {
      let {data} = await axios.get('https://icanhazdadjoke.com', {
        headers: {Accept:'application/json'}
      })
      jokes.push({id: data.id, joke: data.joke , vote: 0})
    }
    this.save(jokes);
    this.setState({
      jokes: [...jokes.sort((a,b) => a.vote < b.vote)]
    })
  }

  newJokes() {
    localStorage.clear()
    this.getJokes()
  }

  load() {
    return JSON.parse(localStorage.getItem('jokes')) || []
  }

  save(data) {
    localStorage.setItem('jokes', JSON.stringify([...data]))
  }

  vote(incOrDec, id) {
    let jokes = this.state.jokes.map(joke => {
      if (joke.id === id) {
        // Handle UP vote if vote + 1 will not go above 10
        incOrDec === 'up' ?
        joke.vote + 1 <= 10 ?
        joke.vote++ : joke.vote = 10
        // Handle DOWN vote if vote - 1 will not go below 0
        : joke.vote - 1 > 0 ?
        joke.vote--
        : joke.vote = 0
      }
      return joke;
    })

    this.setState(st => {
      this.save(jokes)
      return {jokes}
    })
  }

  render() {
    return (
      <div className="JokeApp">
        <div className="JokeApp-sidebar">
          <h1 className="JokeApp-title"><span>Dad</span> Jokes</h1>
          <img src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/rolling-on-the-floor-laughing_1f923.png" alt="smiley-face"/>
          <button onClick={this.getNewJokes}>New Jokes</button>
        </div>
        <Jokes jokeList={this.state.jokes} onClick={this.vote}/>
      </div>
    )
  }
}

export default JokeApp

// Jokes Container class
import React, {Component} from 'react';
import './Jokes.css';
import Joke from './Joke';

class Jokes extends Component {
  constructor(props) {
    super(props)
  }

  render() {

    let jokeList = this.props.jokeList.map(joke => {
      return <Joke jokeData={joke} key={joke.id} onClick={this.props.onClick} />
    })

    return (
      <div className="Jokes">
        {jokeList}
      </div>
    )
  }
}

export default Jokes

// Joke class
import React, {Component} from 'react';
import './Joke.css'

class Joke extends Component {
  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  // handles up or down vote
  handleClick(e){
    this.props.onClick(e.target.dataset.name, this.props.jokeData.id)
  }

  render() {

    let voteColor = [
      'rgb(227, 78, 78)',
      'rgb(227, 123, 78)',
      'rgb(227, 154, 78)',
      'rgb(227, 190, 78)',
      'rgb(227, 221, 78)',
      'rgb(202, 227, 78)',
      'rgb(184, 227, 78)',
      'rgb(162, 213, 35)',
      'rgb(103, 213, 35)',
      'rgb(22, 198, 34)'
    ]

    let voteEmoji = [
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/weary-face_1f629.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/worried-face_1f61f.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/slightly-frowning-face_1f641.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/confused-face_1f615.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/neutral-face_1f610.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/slightly-smiling-face_1f642.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/grinning-face_1f600.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/smiling-face-with-open-mouth-and-smiling-eyes_1f604.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/smiling-face-with-open-mouth-and-tightly-closed-eyes_1f606.png',
      'https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/144/apple/225/rolling-on-the-floor-laughing_1f923.png'
    ]

    let style = {
      borderColor: `${voteColor[this.props.jokeData.vote-1]}`
    }

    return (
      <div className="Joke">
        <section className="Joke-vote">
          <i className="far fa-thumbs-up" data-name="up" onClick={this.handleClick}></i>
          <p className="Joke-vote-score" style={style}>
           {this.props.jokeData.vote}
          </p>
          <i className="far fa-thumbs-down" data-name="down" onClick={this.handleClick}></i>
        </section>
        <p className="Joke-text">
        {this.props.jokeData.joke}
        </p>
        <img className="Joke-emoji" src={`${this.props.jokeData.vote === 0 ?
        voteEmoji[0]
        : voteEmoji[this.props.jokeData.vote-1]}`} />
      </div>
    )
  }
}

export default Joke

After this, we are moving onto working with…

React Router

Using React-Router we can use ‘Client Side’ routing. Traditionally, routing happens on the server side, but with React-Router we can do this on the client side.

Client Side Routing This mimics server side routing without a user having to leave the web page. With this, although the server isn’t serving up multiple pages, React gives us the ability to move around with different URLS, using back/forward browser buttons, as well as bookmark “pages” on our site.

Adding our first route

React-Router isn’t the only routing tool we can use, but it is one of the most popular (in React) and we will be using it to learn about creating and using routes.

Of course, first install by running npm install react-router-dom. We can then include the Router in our app like so. Here, we pull out BrowserRouter from its package, and wrap our App with it.

import {BrowserRouter} from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

To use the routes and have them dynamically render components we would add the following to our App.

import React, {Component} from 'react';
import {Route} from 'react-router-dom';
import Dog from './Dog';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Route path='/dog' component={Dog} />
      </div>
    )
  }
}

export default App;

What is happening here is that we are setting up Route to look for “/dog” to be sent in the URL bar. When that happens, it will render the Dog component.

Using Switch and Exact

You would think that by adding a route of “/” would render the main page component, but this is not the case. It works, BUT, the way Routes work is that they match everything in the route specification.

For instance, if I had two routes, one for “/” and another for “/dog”, the second route would match both “/” AND “/dog”, effectively rendering two components.

To solve this problem, we can use Switch. We use it by wrapping all of our routes with Switch.

  <Switch>
    <Route path="/" component={About} />
    <Route path="/contact" component={Contact} />
    <Route path="/location" component={Location} />
  </Switch>

Switch will now allow only ONE of these routes to be rendered. Unfortunately, Switch works in an orderly fashion, so it will match the FIRST one that it thinks should be matched. IE. “/location” would match to “/” because it looks for the first matching Route, which would be “/”.

We could order the Routes to work properly, but there is a better solution…Exact

<Switch>
  <Route exact path="/" component={About} />
  <Route exact path="/contact" component={Contact} />
  <Route exact path="/location" component={Location} />
</Switch>

Adding exact to your Routes is a good standard is there isnt really a reason not to unless you need to. It will now only match if the path is EXACTLY the string in the specified path.

So far, we have used <a> tags for any links within our site. If we are linking to a route that renders a component(s) however, we need to use <Link> since clicking on an <a> tag sends a get request, re-rendering the page.

React will intercept a <Link> click and perform client side rendering appropriately. Instead of using href we use the prop to inside the <Link> component.

import {Route, Switch, Link} from 'react-router-dom';

<div className="App-nav">
<Link to '/'>About</Link>
<Link to '/contact'>Contact</Link>
<Link to '/location'>Location</Link>
</div>

The above code will use the Links to navigate to the appropriate Route and render the corresponding Component.

If we want to use Links as navigation, instead of in text, we can use <NavLink> instead, which gives us the ability to add an active class to it.

<NavLink activeClassName="active-link" exact to '/contact'>Contact</NavLink>

Using Route with component or render as prop

There is a detailed difference we should be aware of when using <Route component={About}. If we do not need to pass any props in, this is fine. But if we do need to pass props in, it is better to use <Route render={() => {<About {...props}}}. Using component will instantiate a new component every time, while render will re-use the existing component.

Algorithms Course

After completing yesterdays Multiple Pointer pattern, today we are continuing on and beginning with the “Sliding Window Pattern.”

Sliding Window Pattern This pattern involves creating a window which can either be an array or number from one position to another. Depending on a certain condition, the window either increases or closes (and a new window is created). It is very useful for keeping track of a subset of data in an array/string.

An example problem we can use this pattern to solve would be the following:

Write a function called maxSubarrySum which accepts an array of integers and a number called n. The function should calculate the maximum sum of n consecutive elements in the array.

maxSubarraySum([1,2,5,2,8,1,5],2) // 10 maxSubarraySum([1,2,5,2,8,1,5],4) // 17 maxSubarraySum([],4) // null

For now, I will try to come up with my own solution to this, not using any pattern. Here is that solution.

function maxSubArraySum(arr,n) {
    if (arr.length <= 0) return null;
    let sum  = 0;
    for (let i = 0; i < arr.length - n; i++) {
        tempTotal = arr.slice(i,i+n).reduce((acc,cur) => {
            acc = acc + cur;
            return acc;
            },0);
        sum = tempTotal > sum ? tempTotal : sum
    }
    return sum;
}

My solution has a nested loop, which is the reduce function being run inside of a for loop. This equates to O(n2) which is not what we want.

Sliding Window Refactor

function maxSubArraySum(arr,n) {
  let maxSum = 0;
  let tempSum = 0;
  if (arr.length <= 0) return null;
  for (let i = 0; i < num; i++) {
    maxSum += arr[i]
  }
  tempSum = maxSum;
  for (let i = num; i < arr.length; i++) {
    tempSum = tempSum - arr[i - num] + arr[i];
    maxSum = Math.max(maxSum, tempSum);
  }
  return maxSum;
}

This is a VERY clever solution, which only loops over the array one time. What it is doing in the second loop is storing the sum of the added numbers. On the next iteration, it will add the next number, and subtract the value stored at the previous index. This in turn allows us to never have to loop over a sub array to add the values. It is way less work on the CPU and a lot more efficient.

Very cool!

Back to blog...