Larry Price

And The Endless Cup Of Coffee

Getting Started With React Hooks

| Comments

React Hooks are a new feature allowing developers to use state in functional components officially released in React 16.8. Many cryptocurrency converters are using React 16.8. The number of increasing cryptocurrency converters denotes the popularity of crypto trading. Traders who feel it hard to make profits from their trading can take the help of trading bots. Read the trading roboter vergleich blog to find the best trading bots in the market. I am in love with the idea of Hooks, so much so that I’m giving an introductory talk on the topic at an upcoming local JavaScript meetup.

All code from this post can be found in a codepen collection.

Functional Components

A functional component (also sometimes referred to as a “stateless” component) is a method of defining React components with only a render method. These components still take in readonly props and return some JSX, but until now have had no means to perform any stateful logic. The following is a simple functional component that creates a button for canceling a user’s account:

https://codepen.io/larryprice/pen/BMJYwe
1
2
3
4
5
6
const CancelAccountDeletion = ({onClick}) => (
  <button className="btn btn-default btn-lg cancel-account-deletion" onClick={onClick}>
    <span className="glyphicon glyphicon glyphicon-ban-circle"></span>
    Cancel Account
  </button>
);

The component takes in a single prop onClick that is called when the button is clicked.

Adding Stateful Logic The Old Way

Let’s say that we want to add some stateful logic to that component. Marketing has started complaining that users clicking our current “Cancel Account” button contribute to a loss of revenue, and we need to slow that loss down to appease investors this quarter. We get design involved and decide to prompt the user several times to confirm their cancellation. We’ll need to keep track of the number of clicks and the current prompt in state.

Here’s how we might do that on February 5th, 2019, using class components:

https://codepen.io/larryprice/pen/XOgKYd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const messages = ['Really?', 'Don\'t leave me!', 'OK, fine!'];
class CancelAccountDeletion extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      buttonText: 'Cancel',
      clicks: 0,
    }
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.clicks !== this.state.clicks) {
      if (this.state.clicks < messages.length) {
        return this.setState((prevState) => ({
          buttonText: messages[prevState.clicks],
        }));
      }

      return this.props.onClick();
    }
  }

  render() {
    return (
      <button className="btn btn-default btn-lg cancel-account-deletion"
          onClick={() => this.setState((prevState) => ({
            clicks: prevState.clicks + 1,
          }))}>
        <span className="glyphicon glyphicon glyphicon-ban-circle"></span>
        {this.state.buttonText}
      </button>
    );
  }
}

Wow! We’ve nearly tripled the size of our original component here. In this stateful world, we needed to extend the React.Component class, define a constructor to set our initial state, update our state when the button is clicked, and add the componentDidUpdate lifecycle method. The componentDidUpdate method is called on every re-render, so we first check to see if the number of clicks changed before taking any action. If it did, we check to see if we have more messages than clicks and update the prompt text; otherwise, we call the original onClick function from our props and, unfortunately for our sales goals, churn another user.

This is a lot of boilerplate and has a tendency to get complex really fast. If only there was another way!

“Well, actually, Papa Larry,” I hear you interjecting from behind your monitor, “we could do this without a lifecycle method and only one piece of state.” My dear friend. Yes, this code is slightly contrived so that I can show you all the main features of hooks with a fairly straightforward example. Just keep your susurruses to yourself until after the show.

Adding Stateful Logic the New Way

This is where Hooks come into play. Let’s fast-forward from early evening in the American Midwest on February 5th, 2019, to late evening, when suddenly React 16.8 was released and it was officially titled “The One With Hooks.”

Let’s take our original functional component and add state with Hooks:

https://codepen.io/larryprice/pen/vbgwGx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const messages = ['Cancel', 'Really?', 'Don\'t leave me!', 'OK, fine!'];
const CancelAccountDeletion = ({onClick}) => {
  const [clicks, setClicks] = useState(0);
  const [buttonText, setButtonText] = useState();

  useEffect(() => {
    if (clicks < messages.length) {
      return setButtonText(messages[clicks]);
    }
    return onClick();
  }, [clicks]);

  return (
    <button onClick={() => setClicks(clicks+1)}
        className="btn btn-default btn-lg cancel-account-deletion">
      <span className="glyphicon glyphicon glyphicon-ban-circle"></span>
      {buttonText}
    </button>
  );
};

Our Hooks implementation is about half as long as our class implementation. I would argue that it’s also significantly easier to read. Let’s break this down bit-by-bit to discuss each piece of the hooks API:

1
2
const [clicks, setClicks] = useState(0);
const [buttonText, setButtonText] = useState();

At the top of our function, we call the useState method to declare two state variables: clicks and buttonText. useState takes in an initial value and returns a state variable and setter method, which we access locally using array destructuring. In this case, we set the initial state of clicks to 0 and leave buttonText empty.

Behind-the-scenes, React is using our component’s scope to create and track these state variables. We must always define these variables in the same order when this function is executed, or we’ll get our variables all mixed up and our logic won’t make any sense.

1
2
3
4
5
6
useEffect(() => {
  if (clicks < messages.length) {
    return setButtonText(messages[clicks]);
  }
  return onClick();
}, [clicks]);

The useEffect method is essentially a replacement for the componentDidMount and componentDidUpdate lifecycle methods. It takes in a function that will be called after every render. Here we take advantage of closures to test the value of our clicks state variable and use setButtonText to update our buttonText state variable. The second argument to useEffect is an array of state variables to check - if none of the given state variables were changed, the effect will be skipped.

We can call useEffect as many times as we want in our component. This allows us to create a clear separation of concerns if we need to define several different effects.

1
2
3
4
5
6
7
return (
  <button onClick={() => setClicks(clicks+1)}
      className="btn btn-default btn-lg cancel-account-deletion">
    <span className="glyphicon glyphicon glyphicon-ban-circle"></span>
    {buttonText}
  </button>
);

This is our same old render logic, but in this case we’re using the setClicks function returned to us by useState.

Custom Hooks

Design and marketing like this concept of delaying an action and just changing the text so much that they want to use it all over the site. Now we have stateful logic that needs to be reused. This is where the concept of “Custom Hooks” comes in:

https://codepen.io/larryprice/pen/GzENrZ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const useTextByCount = (count, messages, onFinished) => {
  const [text, setText] = useState(messages[0]);

  useEffect(() => {
    if (count < messages.length) {
      return setText(messages[count]);
    }
    return onFinished();
  }, [count]);

  return text;
};

const messages = ['Cancel', 'Really?', 'Don\'t leave me!', 'OK, fine!']
const CancelAccountDeletion = ({onClick}) => {
  const [clicks, setClicks] = useState(0);
  const buttonText = useTextByCount(clicks, messages, onClick);

  return (
    <button onClick={() => setClicks(clicks+1)}
        className="btn btn-default btn-lg cancel-account-deletion">
      <span className="glyphicon glyphicon glyphicon-ban-circle"></span>
      {buttonText}
    </button>
  )
};

Here I’ve created my own hook called useTextByCount that abstracts away the entire concept of the buttonText state variable. We can use this custom hook in any functional component. Abstracting stateful logic is a tall task in class components, but it’s completely natural using Hooks.

Conclusion

Hooks are the result of the React maintainers responding to the way React developers want to write code, enabling us to use powerful stateful concepts in a cleaner, functional system. This is a natural next step for the React API, but it’s not going to deprecate all your class components. Hooks are completely optional and backwards compatible with current React concepts, so there’s no need to make a Jira ticket to refactor all your components tomorrow morning. Hooks are here to help you write new components faster and better, giving you new options when you need to start adding state to that simple button component.

Check out the Hooks Guide and the Rules of Hooks for more information.

Happy hooking!

Notes From All Things Open 2018

| Comments

This is a brief overview of the talks I sat through while attending All Things Open 2018 in Raleigh, NC.

Day 1

First day was okay, but I had trouble finding sessions that interested me and weren’t geared towards introductory use.

Keynotes

The first keynote, “The Next Billion Internet Users” by Angela Oduor Lungati, described the rapid rise in internet users in Africa and Asia. Her team made their app mobile-first, as many users only have access to the internet on a smart device. This allowed the app to be used in many different and unexpected situations. Increased connectivity also allows more people to participate in the world of software. According to a recent GitHub survey, Asia is opening the largest number of repos on the site.

Burr Sutter of Red Hat talked about Istio, Red Hat’s “service mesh” system. It’s a pretty neat way to manage services with k8s and OpenShift. Users can launch multiple service containers with different features and seamlessly direct traffic to these containers based on certain rules. Users could even direct traffic to a new and old version of a container to determine how a new version interacts with a production environment, with end-users only ever interacting with the old version.

“The Next Big Wave” (Zaheda Bhorat) mostly focused on how to create a welcoming open-source project that’s easy to contribute to, especially in a rapidly more connected world. As usual, READMEs and CONTRIBUTING docs are king, as well as good tutorials, wikis, and getting started guides.

In “Design in Open Source”, Una Kravets discusssed how Design Thinking can benefit open-source projects. Unfortunately, it’s really difficult to get designers to participate.

Track Sessions

“Turning ‘Wat’ into ‘Why’” (Katie McLaughlin) brought up a few idiosyncrasies from many different languages and discussed why the language behaves in that manner. No blame; just curiosity.

“Why Modern Apps Need a New Application Server” (Nick Shadrin) was an overview of the new Nginx Unit project, iterating on nginx with a focus on microservice architectures. This system actually launches applications, and several libraries/packages/modules are available for things like NodeJS and Go to enable this functionality. Configuration of any language was nearly identical, and defining the number of running instances was really easy through JSON endpoints. Auto-scaling was also included out-of-the-box.

“Open Data: Notes from the Field” was a panel discussion on how the Research Triangle uses citizens' data to make decisions. Much of the data used is decided upon on a municipal level as opposed to federal or state.

“Using Open Source for Large Scale Simulation in Robotic and Autonomous Driving Applications” (Nate Koenig) was largely a discussion about tools used to simulate robots. Obviously, testing robots in real life can be dangerous and expensive, so advanced simulation technology is crucial to iterating fast on this kind of hardware.

“React Already Did That” (Dylan Schiemann) hit on how React has evolved our ecosystem; components and functional programming will leave a permanent mark on JS development. Although React may not be around in 5 years, it is highly likely that the popular frameworks at that time will be fairly similar (think: Vue, Ionic, Svelte). This talk sort of devolved into a discussion of the speaker’s “competing” technology Dojo, which was somewhat of a precursor to React. It also uses TypeScript, which reminds me a lot of the tech stack we use at Granular.

“You XSS Your Life! How do we keep failing at security on the web?” (David Rogers) was an overview of how easy it is to fall for cross-site scripting attacks in modern web applications. Malicious user input could take down our system or reveal user data, so we should be scrubbing data anywhere it gets entered. Lots of tools available. Although this is touched upon a lot, I know that I’m guilty of just taking user input and using it unthinkingly.

Day 2

I found more relevant sessions to go to during the second day, which surprised me as normally the “last” day of a conference is worse than the first.

Keynotes

“Five Things You Didn’t Know Python Can Do!” by Nina Zakharenko went over things I already knew Python could do. Python runs important code in all industries, and has found itself indispensable in the world of science.

Babel developer Henry Zhu gave a talk titled “Maintainer’s Virtual” describing the world of full-time open-source development. Zhu left his job and works on Babel based on donations from the community. He talked about the guilt associated with taking breaks when people are donating their money to you, and how that easily leads to burnout. He talked about trying not to put too much pressure on yourself to be constantly contributing.

The final keynote, “Money as an Open Protocol” by Andreas Antonopoulos, was… interesting. A dash of conspiracy theory and anarchism made this talk a little uncomfortable. Big banks are not our friends, and this speaker was adamant that we would see the fall of centralized banking in the next 20 years. Bitcoin and friends are the predecessor to a new global digital currency. The choice we’ll be facing soon is whether we have a decentralized open currency akin to Bitcoin as our primary form of money or something more insidious such as “Facebook Coin”, “Google Coin”, “Apple Coin”, or “America Coin.” A fun quote from this talk was “The opposite of authority is autonomy.” Also “If money is the root of all evil, then sudo evil.” Although this talk was captivating, it felt like a pitch for a dystopian novel. Crowd ate it up.

Track Sessions

Kyle Simpson’s “Keep Betting on JavaScript” was probably my favorite session. Kyle gave a brief history of JavaScript, from its creation through its stagnation to the rapidly-evolving language we all know and love today. JavaScript’s failures to change in the 00s was largely due to a lack of unity in the community, ultimately leading to a spec that was thrown away. Other languages began to appear that looked like they would leave JS in the dust. Just as JS was on the brink of death, the community united, new features were specced out, and JS rose from the ashes. Many people still hate on JavaScript, and this is largely due to the fact that they are “emotionally attached to the idea that JavaScript sucks.” JavaScript is lingua franca in programming; it’s readable by developers of many languages, and ideas can easily be expressed. Kyle was very much into progressive web applications, with native apps becoming an unnecessary part of the ecosystem. Every app should have at least one ServiceWorker to guarantee that a tab will continue to exist, even after we get on an airplane. “TypeScript is a really intelligent linter”, Kyle says, but aside from that, can begin to confuse the world we live in if we use too many extended features. Transforming our code with all of these tools can make debugging harder, and can make it difficult for other developers to figure out what we’ve done using “View Source.” “View Source” is the ultimate tool in a new developer’s toolkit, allowing them to see how a site works and helping them develop new ideas. Kyle was weary of many of the new JavaScript features that are machine-centric; code features that will only be used by libraries and generators and never by an everyday programmer. Kyle insists that we should focus on developers first. Even WebAssembly and simimlar ideas are going to make web development a more complicated landscape to enter. Kyle started early and ended late. Further reading: Alan Kay, Douglas Englebart, Tom Dale.

“Cross-Platform Desktop Apps with Electron” (David Neal) was an introductory guide to using Electron, the cross-platform desktop UI technology behind Atom, VSCode, and the Slack desktop app. Starting in Electron seems easier than I expected. Architecture is similar to developing for the web, where we have server-side code and client-side code. It’s better to make calls to the server than to run on the UI thread. Pretty much anything that you can install with npm can readily be used in Electron, including UI frameworks such as React and testing tools such as mocha.

I watched some lightning talks during lunch. Raspberry Pi celebrates their 6th year, something something Blockchain databases, jump-starting an open-source career via blogging or speaking, examples of unconscious bias in AI datasets, all the wrong ways to pronounce “kubectl”, more on Red Hat’s Istio service mesh framework, and ideas for replacing docker with other container tools.

“Framework Free – Building a Single Page Application Without a JS Framework” (Ryan Miller) described the way we used to make websites in 2013 without frameworks, but with all the nice HTML5 features. It’s somewhat important to know how all of these things work under the covers, especially if you have to debug in the browser. It’s not always necessary to have a big, hefty framework. I was somewhat horrified by the number of people in the audience who didn’t know what jQuery was.

In “Intro to SVG”, Tanner Hodges explained the basics of SVGs, when to use them, and when to seek alternatives. Interesting cases included textured content (which rendered significantly smaller as a PNG over an SVG), content that included text (which needed to be checked to verify that the text was rendered as native SVG elements), and photography (which, when rendered to SVG, literally included a data hash of the original image at high resolution, creating a massive file). He also touted the importance of new standards such as webp and webv when displaying content on the web.

In “WTH is JWT”, Joel Lord broke down how JWTs are constructed by combining the encryption method, the payload (basic user information), and a secret key. Although the key can be deserialized and parsed to get to the information, the secret at the end is determined by hashing the key and the payload, so would-be attackers cannot simply change the JWT to gain access to the system without knowing the secret key. Of course, more security measures are necessary to keep intruders from gaining access, such as encrypted sessions and auth servers. The JWT Spec is still in the proposal period, so its definition may still change before finalization.

Conclusion

Pretty good conference. I made a few interesting connections. I learned that a lot of people are in love with Vue right now, TypeScript is still popular, and microservices are the only way to build an application. My biggest complaint was that coffee was hard to come by.

How to Use getDerivedStateFromProps in React 16.3+

| Comments

From a blog post in late March 2018, it was announced that the React lifecycle methods componentWillReceiveProps, componentWillMount, and componentWillUpdate will be deprecated in a future version of React. This is because of the eventual migration of React to async rendering; these lifecycle methods will become unreliable when async rendering is made default.

In place of these methods, the new static method getDerivedStateFromProps was introduced. My team and I struggled at first in wrapping our heads around how to migrate our many uses of componentWillReceiveProps to this new method. It’s generally easier than you think, but you need to keep in mind that the new method is static, and therefore does not have access to the this context that the old lifecycle methods provided.

getDerivedStateFromProps is invoked every time a component is rendered. It takes in two arguments: the next props object (which may be the same as the previous object) and the previous state object of the component in question. When implementing this method, we need to return the changes to our component state or null (or {}) if no changes need to be made.

componentWillReceiveProps

Here’s a pattern we were using in many components throughout our codebase:

1
2
3
4
5
componentWillReceiveProps(nextProps) {
  if (nextProps.selectedTab !== this.state.selectedTab) {
    this.setState(() => { return {selectedTab: nextProps.selectedTab} })
  }
}

This lifecycle method fired when we were about to receive new props in our component, passing in the new value as the first argument. We needed to check whether the new props indicated a change in the state of our tab bar, which we stored in state. This is one of the simplest patterns to address with getDerivedStateFromProps:

1
2
3
4
5
static getDerivedStateFromProps(nextProps, prevState) {
  return nextProps.selectedTab === prevState.selectedTab
    ? {}
    : {selectedTab: nextProps.selectedTab}
}

This code works in exactly the same way, but, since it’s static, we no longer use the context provided by this. Instead, we return any state changes. In this case, I’ve returned an empty object ({}) to indicate no state change when the tabs are identical; otherwise, I return an object with the new selectedTab value.

Sometimes you may have to perform some operations on the new props, but then you can still just compare the result to your previous state to figure out if anything changed. There may be other areas where you need to store some extra state duplicating your old props to make this work, but that may also be an indication that you need to use an alternative method.

componentWillMount

We also needed to replace calls to componentWillMount. I found that these calls were usually directly replaceable by componentDidMount, which will allow your component to perform an initial render and then execute blocking tasks. This may also require adding some loading-style capacity to your component, but will be better than a hanging app.

Here’s an example of a componentWillMount we had originally that blocked render until after an API call was made:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
componentWillMount() {
  this.setState(() => {
    return {
      loading: 'Loading tool info'
    }
  })
  return getTool(this.props.match.params.id).then((res) => {
    this.setState(() => {
      return {
        tool: res,
        loading: null
      }
    })
  }).catch((err) => {
    api.errors.put(err)
    this.setState(() => {
      return {
        loading: null
      }
    })
  })
}

Afterwards, I changed the state to show the component as loading on initial render and replaced the componentWillMount with componentDidMount:

1
2
3
4
5
6
7
8
9
10
11
12
13
state = {
  tool: null,
  loading: 'Loading tool info'
}

componentDidMount() {
  return getTool(this.props.match.params.id).then((res) => {
    this.setState(() => { return {tool: res, loading: null} })
  }).catch((err) => {
    api.errors.put(err)
    this.setState(() => { return {loading: null} })
  })
}

componentWillUpdate

Very similar to the methods discussed above, componentWillUpdate is invoked when a component is about to receive new props and the render method is definitely going to be called. Here’s an example of something we were doing previously:

1
2
3
4
5
componentWillUpdate(nextProps) {
  if (!nextProps.user.isLogged && !nextProps.user.authenticating) {
    this.context.router.history.push('/')
  }
}

And, replacing that usage with componentDidUpdate:

1
2
3
4
5
componentDidUpdate(/*prevProps, prevState*/) {
  if (!this.props.user.isLogged && !this.props.user.authenticating) {
    this.context.router.history.push('/')
  }
}

componentDidUpdate is similar to componentDidMount except that is caused after a change in state or props occurs instead of just on initial mount. As opposed to getDerivedStateFromProps, we have access to the context provided by this. Note that this method also has arguments for prevProps and prevState, which provides the previous versions of the component’s props and state for comparison to the current values.

Conclusion

The deprecation of these lifecycle methods won’t happen until React 17, but it’s always good to plan ahead. Many of the ways my team was using these deprecated methods could be considered an anti-pattern, and I suspect that your team may be in the same predicament.

Quick Start to Vendor Go Dependencies With Govendor

| Comments

I recently spent a few days adapting my Go for Web Development video series into a text-based course. In doing so, I had the chance to investigate some of the new vendoring tools available in Go. As of Go 1.5, “vendoring” dependencies has become the norm. Vendoring means tracking your dependencies and their versions and including those dependencies as part of your project.

In particular, I explored the uses of the govendor package, mostly because it’s supported by default by Heroku. The docs on the GitHub are a lot more thorough than what I’ll go over here.

govendor is easily installed within the go ecosystem. Assuming that $GOPATH/bin is in your path:

1
2
3
$ go get -u github.com/kardianos/govendor
$ which govendor
/home/lrp/go/bin/govendor

Now we just initialize the govendor directory and start installing dependencies. The govendor fetch command is pretty much all you’ll need:

1
2
3
$ govendor init
$ govendor fetch github.com/jinzhu/gorm
$ govendor fetch golang.org/x/crypto/bcrypt

init will create a vendor directory in your project path. Go will check this directory for any packages as though they were in your $GOPATH/src directory. The fetch calls will add new packages or update the given package in your vendor directory; in this case, I’ve fetched the latest versions of gorm and bcrypt.

This might seem painful, but the thing to do next is to commit everything in the vendor directory to your repository. Now you have it forever! This means that anyone who wants to run this version of your code in the future doesn’t have to worry about dependency versions and can instantly run your package with a valid go install.

If you don’t want to add all these packages to your repository, I don’t blame you. You can get around this by committing just your vendor/vendor.json file and then using govendor sync to install the missing packages after downloading your source code. This should be familiar to anyone who’s used bundler in ruby, virtualenv in python, or npm in Node.JS. If you’re using git, you’ll want a .gitignore with the following:

1
2
vendor/*
!vendor/vendor.json

This will ignore everything in vendor/ except for the vendor.json file which lists all your packages and their corresponding versions. Now, to install any packages from vendor.json that you don’t already have in your vendor directory:

1
$ govendor sync

govendor is a pretty powerful tool for vendoring your go dependencies and getting your application Heroku-ready, and I recommend checking out the docs for a more advanced overview. There are also many other vendoring options available, including an official go vendoring tool called dep that works with go 1.9+. dep will most definitely play a big role in refining the ideas that these third-party tools have created and the go ecosystem will become more stable.

Redirecting to Your Main Site With Heroku

| Comments

We have a lot of domains that we want to redirect to the same server, but we use a DNS service that does not allow doing a domain forward, and we’re not allowed to upgrade. I wanted to do this in the simplest way possible, so I created a workaround using a PHP script and Heroku. The source discussed in detail in this post is available on GitHub: https://github.com/larryprice/simple-heroku-redirect-app.

The goal here is for users to visit a page and then be immediately redirected to the new site. I’ve defined two environment variables to be used in this project: SITENAME, a human-readable name for our website, and SITEURL, the full URL that we actually want the user to end up on. I’ve defined a PHP file called index.php:

index.php
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
  <head>
    <title><?php echo getenv('SITENAME') ?> - You will be redirected shortly...</title>
    <meta http-equiv="refresh" content="0;URL='<?php echo getenv('SITEURL') ?>'" />
  </head>
  <body>
    <p>Please visit the official <?php echo getenv('SITENAME') ?> site at <a href="<?php echo getenv('SITEURL') ?>"><?php echo getenv('SITEURL') ?></a>.</p>
  </body>
</html>

The important piece here is the <meta> tag, which actually does the redirect for us. The only PHP code here are echo getenv commands that render our environment variables in the template. Since I’m a PHP novice, there may be a better way to do this, but the echo works just fine.

We also need to tell Apache how to serve the application. We want to match any routes and render our index.php. So we create an .htcaccess file:

.htaccess
1
2
RewriteEngine on
RewriteRule . index.php [L]

To satisfy Heroku, we need to list the dependencies for our PHP application. Fortunately for us, we don’t have any dependencies that Heroku does not provide by default. We’ll just create a composer.json file in the root of our project with an empty object:

composer.json
1
{}

That’s everything we need. You could recreate the project, but you could also just pull down the project listed above and push it up to Heroku:

1
2
3
4
$ git clone https://github.com/larryprice/simple-heroku-redirect-app.git
$ cd simple-heroku-redirect-app
$ heroku create
$ git push heroku master

With your application available on Heroku, we still need to set the environment variables described earlier as config variables:

1
2
$ heroku config:set SITENAME=yourgooddomain.com
$ heroku config:set "SITEURL=Your Good Domain's Website Name"

Now tell Heroku all the domains that will be accessing this application. These are the domains you want users not to use:

1
2
$ heroku domains:add yourbaddomain.com
$ heroku domains:add www.yourbaddomain.com

Now you just need to add the records indicated by the above command to your DNS records. These will probably be CNAME records pointing from @ to yourbaddomain.com.herokudns.com or www to yourbaddomain.com.herokudns.com.