Living in a Material World

The more I work with React, the cooler it seems.  I know- I’m way behind.  React is already uncool, Vue is the new hotness.

However, every time I start writing custom HTML components in plain ‘ol Javascript, I end up with a pattern that looks a lot like React.  I then say to myself: “Why am I recreating a crappy version of React instead of just using React?  People smarter than me have spent many hours making a much more optimized version of this monstrosity I’m building”.  Then I look around to make sure no one heard me talking to myself.

It’s at that point that I run the “create-react-app my-app” command and really get down to business.

I started a project with React almost a year and a half ago, but just couldn’t wrap my head around the router.  It’s not that React Router (v4) wasn’t well built (though I might have thrown some insults at it in a frustration-fueled rage), but I’d been using Angular at work, and the router philosophies are pretty different between those two.

I started a new project with React (integrating some Phillips Hue lights into a ui) a couple weeks ago, and decided to give it all another shot.  The first few hours of figuring out the routing was still a struggle, but then it kind of clicked.  The <Router> declaration in React is a bit like the router-outlet in Angular, with the declaration of the route all in one.  I don’t think I’d really grasped that originally, and it led to a mess of an application.

But the router isn’t the point of this short post.  This one is about integrating Material-UI with React and how cool composable components are when you start to understand how to really use them (note that I said “start to understand”- I have a long way to go).

So, I’d already created some simple components to get everything working.  I’d also cooked up a simple Node server to serve as a fake API.  I hadn’t bought the smart lights yet- but wanted to test, so I just copied the JSON structure from the documentation, pasted it into a file on my computer, and set up a server on localhost to respond to the same endpoints the actual API would and serve up the JSON.  It works surprisingly well!

One of those components displays all the lights available (2 currently).  That LightPanel component is made up of LightSwitch components- one for each light.  The focus early on was to get them working.  Once I reached that point, the time had come to actually make them look presentable.

Too often this is where I end up burning a lot of time.  I have a habit of trying to create nice looking css on my own- but this time I learned my lesson.  I’d let the experts help out, and use the Material UI library.  It integrated pretty easily, As a test, I switched my LightSwitch jsx from simple custom radio buttons to the Toggle component and it instantly looked better.  Success!

But the really cool part was when I decided to use the Card element for my main LightPanel grid.  Again- this will show all the switches, their status, and allow a user to turn them on or off.  Each light gets its own Card in the grid.  The functionality to get this info and do these actions was already there, I just had to integrate it into the Card element.  I thought the best way would be to just embed my LightSwitch component into the Card’s ‘text’ section.  This worked, but didn’t look quite right.  I realized that it would really go best in the Card’s ‘title’ section.

But the title section is meant to be passed info as attributes- not have text inside tags.  Instead of <CardTitle>My text here</CardTitle>, it should be <CardTitle title=”My text here” />.  I wanted to basically embed a custom React component into the “title” attribute.

Thinking “there’s no way this will work”, that’s exactly what I did:

I saved and waited for my command line output to give me a wall of red text, but none appeared.  Fingers crossed, I opened my browser, and there it was, in all its glory.  The card with my custom switch component embedded as the title attribute- toggle functionality and all!

So thanks all around: to React, to Material UI, to the wonders of Javascript!

Advertisements

That fresh inline style

React is cool.

I know- React is so 2016- but I’m generally late to the party anyway.  I’d read good things, but hadn’t had a chance to use it in an official project (you know, the ones that pay real money).  So I started a side project using React JS.

Generally, it seems more modular than Angular 2.  When working on an Angular 2 (which I love) app, the approach is usually “Angular all the things”.  You are going to make a single page app.  It is going to use the router and Typescript and so on.  Very nice to have your decisions made for you.

With React, I have a bit more flexibility- but have to make some more decisions.  I can use it just to create some reusable UI components (working on a React based form for my static main website now).  Or I can integrate with a router and create a full blown single page app.  I wanted to test everything, so for the side project (a collaborative event creation and commenting app for scheduling our weekly beer-drinking night) I’m integrating react-router and going full-blown SPA (single page app- without all the typing).

This post, however, is about a trap I fell into with styling the app.  I fall back to the OG Javascript days when getting going with a new framework- and it can lead to trouble (see post from a while ago about me trying to manipulate the DOM directly in Angular).  So, when I wanted to use JS to dynamically offset a static header, I tried to getElementById and failed miserably.

React (and Angular) has lifecycle hook methods.  When your view is loaded and the DOM is ready, componentDidMount fires.  It seemed like a good place to add my little function to get the header element height (which will depend on the width of the user’s viewport) and add that much padding (plus a little breathing room) to the main wrapper.

setHeader() {
    const header = document.querySelector('#header');
    const wrapper = document.querySelector('#content-wrapper');
    //have to make sure header exists or error
    if(header) {
        wrapper.style.paddingTop = `${header.clientHeight + 16}px`;
    }
}

Please note: the above is not exact- that version of the function is long gone, but should give you the idea.

And it did fire properly in the lifecycle hook.  But the height of the header wouldn’t always change.  Turns out- in React (like in Angular), directly manipulating the DOM is a Bad Idea.  I haven’t dug too deeply into this, though I would guess it has something to do with the diffing/shadow DOM aspect.  But there is a good and easy fix.

Don’t manipulate the DOM directly.  Part of the beauty of these front end frameworks is that you can dynamically set styles.  Some developers set all their styles directly in their jsx.  So, instead of the above function, I used this

//call inside componentDidMount so the DOM is ready
setHeader() {
    const header = document.querySelector('#header');

    //have to make sure header exists or error
    if(header) {
        this.headerHeight = header.clientHeight;
    }
}

And in the jsx, set the style’s paddingTop attribute to the end value of this.headerHeight.  I would display it here, but for some reason WordPress won’t let me show html tags.  Sorry!  But the moral stands- this method works.  Knowing the native JS DOM manipulation methods is very useful, but it can help to forget them sometimes when using a front end framework.

Also, if anyone knows why html tags cause such trouble, let me know!  I tried both the <code> and <pre> tags, but html just comes out blank (works with other kinds of code it seems).

Reactular – Or, How I learned to Stop Worrying and Love JS

Aka: Why modern Javascript frameworks are sometimes like characters from Eyes Wide Shut, wandering around at an upscale swingers party…

So far, using React has been a lot of fun- but I have noticed a bit of a learning curve.  The basics are nice and easy- particularly with the ‘create-react-app‘ utility.  If you haven’t used that, definitely check it out- it takes away almost all the setup of the application (webpack config, dev server, etc) and lets you get straight to the coding.

Usually, I’m one of those people that wants to build everything myself to understand how it works, but there are a couple exceptions.  Working with calendars and dates is one- I’ll always use a module/plugin for that.  My brain starts melting even thinking about trying to get that right.  Setup for JS frameworks is another.  We had to do all the config for an Angular 2 project through the release candidates and now into production and it was a bit of a nightmare.  No fault to the Angular 2 (sorry, just Angular) folks- their framework is awesome- but setting it up was not easy.

Anyway, getting a ‘hello world’ app going in React is great, but if you’re going to use it for anything beyond really cool UI components, things get tricky fast.  Some of that is managing/updating state- so relying on options like Redux can be a great option, but in this case, I wanted to see how far I can get on my own.  The test app I’m building (event tracker and commenting system) won’t be too complex, so it should be a good learning experience.  Keeping the functionality in one main container component and passing down anything (via props) that needs updating has worked well so far (and leaves good refactoring opportunities down the road).

Enough rambling- the point of this post is not React’s learning curve- it’s actually about how they’re all just JS behind the creepy bird mask and hooded cloak.  Sometimes, lessons learned in Angular can be applied (almost copy/pasted) directly to React.

Example: I have a filter option for events in my React app.  It’s in a sidebar that appears with every route view.  Click an option (current, past, all) and the sidebar events filter by date.  However, I didn’t want this to change the actual route- a user should be able to check out all the options before changing that, so the filter categories aren’t true links (in the React Router ‘Link’ sense)- they just set a context variable (this.filterType) and fire the method.

That last part is important, because React Router’s Link module comes with a nice option for ‘activeClassName’- set it to equal whatever class you want and when that Link is showing, that class is applied to that link.  I wanted the same effect, but my category headers aren’t Links.

Turns out, you can achieve this pretty easily.  I already have the filterType class variable.  I also know you can bind React’s className attribute to the result of a Javascript conditional.  I’ve also done something very similar in an Angular template file.  The code that makes it work in React (inside your element in JSX) is below. This one is on the ‘Current’ category filter button:

className={this.filterType === 'current' ? 'link-active' : ''}

In Angular (2) it might look like:

[ngClass]="{link-active: filterType === 'current'}"

Not exactly identical, but pretty close, and the idea is the same.  And pretty cool!  It really helps expose that it’s JS all the way down, even if it’s wearing a mask and wandering around the party telling people it’s HTML.  At the unmasking ceremony you get to see exactly what you got yourself into.

You got your HTML in my Javascript!

I do love that bit.  Anyway, I’m with Officer Reeses.  Not on the whole “murder car accident victims and take their idea” front, but definitely that two great tastes can taste great together.

Most of my frontend work so far has been in Angular 1.5 and 2 (and of course, regular JS and jQuery in the good old days).  I’ve really been liking Angular 2 (may have mentioned that previously)- when paired with Typescript, it really makes for a nice dev experience.  I know es6 classes is somewhat controversial, but it’s nice as an organization tool for code if nothing else.  Having that class grouping and inheritance (I know it’s just a wrapper on normal JS prototyping, but it’s still nice), as well as a module system for easily including code/components from other files allows for small, related groupings of code more naturally (at least, in my opinion).

However, I’ve also started getting up to speed on React and so far I’m really loving it.  Using the Babel transpiler (or, I guess you could use Typescript in React as well- though it’s not as common), you can take advantage of classes and module loading and all that other goodness.  React seems a bit less of a wrapper than Angular does- example: There is no *ngFor looping in React- if you want to loop over an array of items and display them in a view, you just use a good old array method (map, forEach, etc).

And I think that’s where some of the Angular vs React argument comes from.  Do you prefer more html in your javascript or more javascript (or Angular’s version of javascript) in your html.

Having worked with one and dabbled so far in the other, it really seems like a toss up.  Once you’ve created a few modules in each, each approach seems to make good sense.  It would really just be a personal preference- but both make it easier to create the quick, responsive web apps people are starting to come to expect (unless you visit any food blog or other site littered with ads- those are just terrible).

So, did Angular get Javascript in your HTML?  Did React get HTML in your Javascript.  Who cares?  They’re the great tastes that taste great together!