Some thoughts on SlideRank improvements

I’ve successfully deployed a sort of working, somewhat styled version of SlideRank (which even has a name!) to Heroku. And immediately I see things that need improvement.

  1. There’s no way to delete an album. That needs to happen. And if I really want to get into that, that means signing in users and authenticating their actions and permissions. That may be a hair more than I want to invest in this particular project. The alternative is that anyone would be able to delete anything. Perhaps that’s okay for now.

  2. The home page should have newly added albums, as well as popular albums. Perhaps 5 of each, then the unsorted list of them all.

  3. There should be an indication that you’ve submitted a vote, and it should clear out the old images before loading new ones.

  4. It would be nice to have albums on the error page. Or just redirect to the home page.

Migrating React Router from 3 to 4

I was working on understanding how to make React relevant beyond a single page app, and I came across this tutorial by Krithika Muthukumar.

When I got to the end, and I knew what I expected each piece to be doing, nothing happened. None of the components worked at all. I dug in deeper, and saw that some of the required packages were outdated, and after some elimination processes, I found the problem: it used React-Router 3, and the latest version, 4, has changed significantly.

As a challenge to myself, someone who is pretty new to React and with no previous experience with React-Router, I attempted to migrate the tiny, crazy simple app to React-Router 4. And after some brow furrowing and chin scratching, I made it work. This may not be the best way to do things, and there are some things I thought would work but don’t (and I still don’t know why). But it works, and I’m happy about that.

I also made this crazy simple app a tiny bit more complicated by adding a header with links to each of the two pages.

Here’s what I did. (Click here for the Github repo)

Install React Router 4

npm install --save react-router react-router-dom

src/index.jsx

In the index, we’ll have React.DOM render the App component, instead of a Router component. That means we don’t need to import anything from react-router or ./routes, and we remove the Router component.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app';

require('./stylesheets/base.scss');
require('./stylesheets/home.scss');
require('./stylesheets/contact.scss');

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

src/components/app.jsx

First, we’ll need to import BrowserRouter from react-router-dom, as well as the Routes component and a new Header component.

Our App is going to return BrowserRouter so all the child components will have access to the routes. There are a couple of things of note about BrowserRouter, which replaces Router. It comes with history included, so we don’t need to worry about managing it. Also, it can only take one child, so we put everything in a <div>.

import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import Header from './views/partials/header';
import Routes from '../routes';

const App = () => (
  <BrowserRouter>
    <div>
      <Header />
      <Routes />
    </div>
  </BrowserRouter>
);

export default App;

src/routes.jsx

Back up to Routes. This is a bit different than in React Router 3. We’re going to use Switch, which finds the first matching route and ignores the rest. For the catchall route, we can render() a function to Redirect back to ‘/‘.

import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Home from './components//views/home';
import Contact from './components//views/contact';

const Routes = () => (
  <Switch>
    <Route exact path='/' component={Home} />
    <Route path='/contact' component={Contact} />
    <Route path='*' render={() => <Redirect to='/' />} />
  </Switch>
);

export default Routes;

src/components/views/partials/header.jsx

I created a partials directory for the Header component. It needs to import Link from react-router-dom to use the routes in Routes.

import React from 'react';
import { Link } from 'react-router-dom';

const Header = () => (
  <div id='Header'>
    <span><Link to='/'>Home</Link></span> | <span><Link to='/contact'>Contact</Link></span>
    <hr/>
  </div>
);

export default Header;

src/components/views/home.jsx and src/components/views/contact.jsx

The only significant change here is to remove the componentDidMount() method, which means we don’t need to import anything from react-router.

import React from 'react';

const Home = () => (
  <div id='home'>
    This is the home page.
  </div>
);

export default Home;

And

import React from 'react';

const Contact = () => (
  <div id='contact'>
    This is the contact page.
  </div>
);

export default Contact;

And that’s all there is to it. I’m extremely grateful to Krithika Muthukumar for creating the tutorial originally. I have been having a very hard time finding help wrapping my brain around how a multi-page React/Express app would work, and this has helped enormously. I’m also grateful to React Training for the documentation and for making React Router in the first place. Powerful stuff here.

Understanding spread

One of my biggest sets of frustrations comes from not being able to understand a concept, method, tool, etc., until I’ve used it a bit. And once it clicks, I can’t understand how I went so long thinking it was complicated to grasp.

Right now, I can’t understand why it took me so long to grasp the array spread operator. I must have read the MDN page half a dozen times, barely retaining enough to remember what it was called. How many times did I Google “three dots js” and close the page, eyes glazed over?

It’s nice, especially since I was just recently introduced to the concept of passing by reference and how that can screw up your immutable data structures. That was a DTC issue, where I just tried to push one object into an array, then use the array again only to find that the data had been changed. That’s how I came across Object.assign, which passes only the values of an object, not a reference to the original.

And that was how the spread operator was explained in The Road to Learn React. It’s like Object.assign, just for arrays (as well as objects in React via babel-plugin-transform-object-rest-spread). And suddenly, I get it. Okay. What’s next?

Hoping to see the forest for the trees

There has to be a good reason for React, right? So far, it seems like a lot of passing information from one place to another without any apparent reason and a lot more typing. If you want to make something, you can’t just make it. You have to make what it might be, then set up the ability to make it, then make it.

Let’s make a button:

<button type='button' class='pretty-button' onclick='someFunction()'>
    Click Me!
</button>

But in React, you need it to be a functional stateless component, so it’s more like:

const Button = ({ className, onclick, children }) =>
    <button type='button' onclick={onclick} className={className}>
        {children}
    </button>

But that’s not enough, because that component is inside a parent, where it gets its properties:

<Button className='pretty-button' onclick={someFunction>
    Click Me!
</Button>

So at least in this case, you’ve more than doubled how much you need to write (which they say doubles your chances for a typo or other error). I’m sure there’s a good reason for doing things this way, but I sure haven’t seen evidence of it yet.

Starting React

I just started my first local React app. Wish me luck.

Using: The Road to Learn React

This book goes over a lot of ES6 stuff, which is good, as I need practice with those, and it also introduced another fun tool:

Hot Module Reloading

This appears to be part of Webpack, which is included in create-react-app. Add if (module.hot) module.hot.accept(); to index.js and you don’t have to refresh every time you make a little change. Nice.

Node, Express, Mongo, and more

I’ve almost finished Colt Steele’s Web Developer Bootcamp course, and things are starting to click. It’s a big jump from just HTML/CSS/JS to making a full stack app with dynamic content, data stored in a database, users who can log in, etc., etc. There are a lot more moving parts, and it’s often unclear where one part starts and the other ends.

But I think I understand enough of how all the parts work together that I could halfway comprehend enough Stack Overflow questions to make something of my own. I know that a voting app is part of FCC’s back-end curriculum, but I have an idea about how to implement that sort of thing. I’ll keep mulling that one over before I commit to spending too much time on it, though.

(And speaking of commit, I’m getting a lot more comfortable with Git, which is nice. It’s becoming increasingly apparent that Github alone isn’t sufficient.)

I’d also like to go back to FCC and work on their data-visualization and back-end curricula. They’re sparse educationally, but the projects look like they have the right kinds of challenges built into them. And I think the experience with Node (or perhaps Express) will make the parts of React that I wasn’t catching on to a few months ago more comprehensible.

Refactor, make a bug, fix bug, refactor, make a bug...

Today I’ve been working on allowing users to add the number of smelting, crafting, etc. stations they have in operation. That will affect the time required to make the materials in question.

I added a simple number and +/- buttons that would count up or down when clicked. But in order to do that, it screwed with how the needs and inventory lists are created. So I reworked it. Rather than just creating the items it needs, now it creates and hides every item upon load and only unhides the ones needed. Much easier said than done. And much easier done in jQuery than vanilla JS. But a challenge is a challenge, and I’m not using jQuery this time.

Much later I got everything working as it used to (but now with shiny +/- buttons!) and I found another bug. At least this was an old one, not one I created in this refactor process.

I found that if you have inventory for a material needed more than once, the inventory is counted twice. Tracking that one down was entertaining, and squashing it was downright fun.

This morning I was able to implement to coal slider, another rewarding accomplishment, especially because I got to work on my new flexbox skills.

Oh, and because I didn’t want to bother digging out my Photoshop disks, I installed Gimp to work on the background image. What a clunky, user-hostile thing to inflict on people. I’d almost call it overpriced. For similar reasons I downloaded OpenOffice with similar sentiments. Sigh.

Every new tool is like an egg

I’ve spent some of the last couple of days working on styling DTC. I have limited experience with design, and if I look at just about anything long enough, I can’t tell whether it looks good or bad anymore.

At this point, I don’t know if what I’ve done looks bad, but it certainly looks nicer than the completely unstyled site that it has been so far. It looks more like someone put some thought into it. At the very least, everything has its own space, and it’s responsive.

As I’ve said before, I’m easily persuaded, and this time, it was this video that convinced me to use CSS Grid and dive headfirst into the newer methods of laying out pages. I watched the video again to get the keywords to use, and I was on my way.

And then I was immediately stuck. It didn’t work. I didn’t understand what I was doing. So I read more at CSS-Tricks. I still didn’t get it, so I checked out examples from Grid by Example. It still wasn’t working until I got to Redefining Grid Areas with Media Queries.

Suddenly, it worked perfectly. Just define your grid areas with names in grid-area, and tell them where to go in the parent by literally creating a grid with those names with grid-template-areas. No need to worry about telling each row and column where to start and stop–and for the mobile section, it’s just a list of area names in the order you want them to appear. Amazing.

And then, for no apparent reason, I started understanding the rest of it. What hadn’t been working previously was working now. It must have been something I was doing wrong, but I still have no idea what that was. It was like I had been tapping on an egg, trying to get inside, and as soon a small crack appeared, I was able to get to the egg effortlessly.

It happened when I decided I wanted to make my input fields align with each other, rather than the jagged placement based on the length of each one’s label. For that, I decided I would learn Flexbox. Again, initially it made no sense. But once I started to grasp the concepts behind it, the styling began to flow.

Well that was cool

There’s nothing like a bit of praise first thing in the morning. I woke up to this from the Rockbite Games representative who hangs out on the Deep Town subreddit.

I’ve shown this to our team, and they love it! Keep it up, the bots are proud of you! No, really this is very impressive. We’ll try to check the GitHub repo on the weekend if there is some time.

That’s all, but that’s all it takes. A hint of recognition for my work, and from someone whose opinion is more than slightly informed.

Maybe I should get to commenting on my code…

Quick JSHint/ESLint VSCode/Sublime note

I recently switched from using SublimeText3 to VSCode, mostly based on the recommendation of this video. Yep, I’m easily persuaded.

I like it a lot. There are some differences I don’t particularly like, but in general, I find it more intuitive. I feel like I don’t have to spend as much time figuring out how the program works, so I can spend more time figuring out how to make my own code work.

My biggest complaint is that it came with ESLint pre-installed, and I couldn’t for the life of me make it work. I still don’t know what I did wrong. But no matter. It’s not the only ball game.

So I installed JSHint, which I had been using in Sublime. The problem is that it shows errors differently. In Sublime, it puts an icon in the margin to tell you that there’s an error, while in VSCode, it puts a squiggly underline under the error, which is often a single character. It’s almost impossible to see that it’s indicating an error.

I’m sure there’s an option to make it look less bad, but I’m disappointed that it doesn’t look good by default.