An Example of JavaScript Double Negative

javascript double negative
Image credit: https://flic.kr/p/2oNKyk

I remember the first time I saw JavaScript double negative syntax. It confused the heck out of me – so much so, I thought it was a mistake.

Over time, I have seen other developers equally confused. It must get asked in Slack at least once a quarter, if not more.

In case you aren’t sure, let’s quickly cover exactly what we are talking about here:

{ isAuthenticated: !!localStorage.getItem('idToken') }

The point of interest here being the double negative / double bang / !! / double exclamation marks. I put all the alternatives I can think of in, in the hope that it helps others searching for similar.

It’s also worth pointing out that double exclamation marks are not a single operator. I guess that makes it all the more difficult to Google, and understand.

Just Tell Me What It Is

For the impatient, using Javascript double negative / not not will coerce your value to a boolean, and ensure that the output is of type boolean.

To translate that from technobabble:

The first ! will convert a value that isn’t either true or false into a value that is  true or false, and then invert it.

The second ! will invert it again.

Confusing?

An example illustrates a potential use case, which hopefully will make it slightly easier to understand.

Just Show Me An Example

Here is a real world example from an authentication reducer I am currently working on in a React / Redux project.

Let’s look at the code as it stands before adding in the double negatives:

import {
  LOGIN__FAILED,
  LOGIN__SUCCESS,
  LOGOUT__SUCCESS
} from '../constants/ActionTypes';

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken')
}, action) {

  switch (action.type) {

    case LOGIN__SUCCESS:
      return Object.assign({}, state, {
        isAuthenticated: true,
        userId: action.userId,
      });

    case LOGIN__FAILED:
      return Object.assign({}, state, {
        isAuthenticated: false,
        errorMessage: action.errorMsg
      });

    case LOGOUT__SUCCESS:
      return Object.assign({}, state, {
        isAuthenticated: false
      });

    default:
      return state;
  }
}

Most of this is not that interesting in the context of this particular example.

I have highlighted line 9 where localStorage is used to retrieve the user’s idToken, should it exist.

There is a bug in this code.

The default case of the switch statement means that when a user first loads the page / before they have ever logged in, the default state would return:

{
  sendingRequest: false,
  isAuthenticated: null
}

Instead, I want it to be:

{
  sendingRequest: false,
  isAuthenticated: false
}

I could use a ternary operator to fix this:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken') ? true : false
}, action) {

And this would work, but WebStorm moans at me that I can do better:

webstorm-can-be-simplified
WebStorm telling me I suck

I make the change:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: !!localStorage.getItem('idToken')
}, action) {

Why does this work?

Because by localStorage.getItem(‘idToken’) is going to either return me a string (containing my locally saved idToken), or as we have already seen, a null.

If we check whether a string is not (!) something, we would get false – because a string is definitely something.

It therefore stands that if a string is not not something, then it must be true.

Likewise, if we check if a null is not (!) something, we would get true – because a null is definitely nothing.

It equally therefore must stand that if a null  is not not nothing, then it must be false.

Still confused? Don’t feel down about it. It took me ages to grasp this, and it’s so unusual that it really won’t come up that frequently.

I would even go as far as to say consider sticking with the ternary operator approach. It is simply easier for most developers to immediately understand, even if WebStorm moans about it.

How I Fixed: Redux Form onSubmit Proxy Object

It’s late, I’m tired, but no excuses, this took me about 45 minutes to figure out even with the documentation.

The problem:

I wanted to use Redux Form (v6.0.5) to handle form submissions for a simple login form.

I could get the form to render, and submit, but when I submitted my data, rather than getting back the JSON data as expected, instead I got a funky proxy object:

Proxy {dispatchConfig: Object, _targetInst: ReactDOMComponent, _dispatchInstances: ReactDOMComponent, nativeEvent: Event, type: "submit"…}

Annoyingly now I cannot reproduce the issue that made the Proxy object appear in the first place, but here is sample working code that fixed the issue:

import React, { Component } from 'react';
import LoginForm from '../components/LoginForm';

export default class LoginPage extends Component {

  doLogin(formData) {
    console.log('Submitted form data', formData);
  }

  render() {
    return (
      <div>
        <LoginForm onSubmit={this.doLogin}/>
      </div>
    );
  }
}

And the login form itself:

import React  from 'react';
import { Field, reduxForm } from 'redux-form';

const LoginForm = (props) => {

  const { handleSubmit } = props;

  return (
      <form onSubmit={handleSubmit}>

        <label htmlFor="username">Username</label>
        <Field component="input"
               type="text"
               name="username" />

        <label htmlFor="inputPassword">Password</label>
        <Field component="input"
               type="password"
               name="password" />

        <button type="submit">Sign in</button>

      </form>
  );
};

LoginForm.propTypes = {
  onSubmit: React.PropTypes.func.isRequired
};

// Decorate the form component
export default reduxForm({
  form: 'login' // a unique name for this form
})(LoginForm);

There is a section on this in the documentation, but for the life of me, I couldn’t get my head around it.

All I know is, it seemed to like it more when I switched my LoginForm from a class to a function. But as I say, when I tried to revert my changes back to write up this blog post, it worked as a class all the same.

Hopefully this saves someone some time in the future.

2x Video Playback, Social Sharing, and More

I want to share with you what I have been working on lately in regards to CodeReviewVideos – aside from the video content, of course.

Actually, before I do – on this subject:

I will always put the video content first.

For those that do not know, CodeReviewVideos is not my full time job. By day I am currently a contract Symfony developer here in the UK.

Within the past two weeks my family and I have welcomed our second child into our lives, and we are all still getting used to the changes this has involved.

Also, we moved house. Crazy timing.

And our first child started primary school.

Yep, it’s nuts round here.

Anyway, given all this, as I say, the main focus for me has always been adding more video content to the site. I strongly believe this is the best use of my time – sharing my knowledge to help make learning Symfony easier and faster for you.

This often means I will spend time making videos instead of adding new features to the site. It’s always about trade offs. Hopefully you agree with my prioritisation, but if not – do feel free to leave a comment, or email me, or send a support message, or tweet me… or any other method you like. I love talking with you.

Site Improvements

With all that said, I do have a big outstanding list of “stuff” I want to do with the site.

A big thing is adding site search, and again, this week a member has requested this. I know, I know, I hear you – it sucks that this feature is lacking.

But rather than focus on lack, let’s look at what I have added.

On Monday the final video in the Pagination, Filtering, and Sorting for Twig and your REST API series was added.

This series compliments the earlier Symfony 3 with ReactJS and Angular series, building on the same foundations.

Future series will involve React more heavily. I am still unsure about supporting Angular 2, however, as I am really not a fan. If you’re pursuing Angular 2 do please let me know. If it is popular I will find a way.

Video Speed

You can now change the video playback speed on any video between 0.5x, 1x, 1.5x, and 2x.

I have had feedback to say I speak too quickly at the best of times, so 2x may be pushing it.

Hopefully you find this useful if wanting to rapidly digest the more talk-y sections.

I have tested this on desktop and iPad, but have struggled to get it working on mobile. Please leave feedback if you are having any problems.

Social Sharing

I have added social sharing buttons to the bottom of each course and video page.

I would be incredibly grateful to you if you would share any content you have found / find useful with your friends and followers.

It is my aim to make this site as useful as possible to my fellow developers. Many of these video topics have come about after struggling long and hard to find a working solution. If I can help you or your colleagues in any way, please spread the word.

It is truly humbling to have helped so many like-minded developers around the world, and I hope to continue doing so for many years to come.

Subscription Improvements

As mentioned above, I am aware some parts of the site are in need of improvement. Today I have added the ability to see your current subscription details, and your next billing date.

Honestly, these things should already be in place. It pains me that they are not. Hopefully from reading the above you can understand why.

Whats Next

Aside from continuing to improve the site as a whole, the two major improvements that are forthcoming are:

  1. Site search – I am working to integrate Elasticsearch into my back end.
  2. Mailing List – I rarely send anything out to the mailing list. I know I need to get better at this. I want better content, and a better schedule. It’s all on me to improve this.
  3. User Management via REST API – I am completely re-writing the back end of CodeReviewVideos currently, switching from Twig to a RESTful API using FOS REST Bundle. It has been a long time coming, but will effectively be the version 2.0 of CodeReviewVideos.

I can’t wait.

Video Content

Please, please, please – let me know what you want to see on the site. I have my plans for what I want to cover, but it’s more importantly about what you want to see.

I can guess all day long, but if you tell me, everyone wins.

Thanks,

Chris

Be Careful What You console.log

I caught myself out.

What’s worse – I thought I was helping myself in doing so!

Let me set the scene:

I have a project where I need to find the most recent file in a directory.

There’s probably a hundred or more ways to do this, but my way – in this instance – goes a little something like this:

readDirectory(data.filePath)
  .then(dirContents => {
    return findMostRecentFileInList(dirContents);
  })
  .then(mostRecentFileName => { // etc

It’s a node JS project btw.

Each of the files in the directory would be in the format {timestamp}.csv .

There exists a possibility that the files may be restored from backup, therefore I couldn’t rely on the “created at” dates.

Anyway, this all works quite well.

The directory contents during test looks something like this:

➜  my-dir git:(my-branch) ✗ ls -b1    
1471809864936.csv
1471896885574.csv
1471896978085.csv
1471896985167.csv
1471897173301.csv
1471897251818.csv

And here’s the contents of the findMostRecentFileInList  function:

/**
 * Expects to receive a list of files in the format ${timestamp}.ext
 * Sorts the files on file name, returns the second most recent
 * The first most recent would be the new file
 */
const findMostRecentFileInList = (list) => {
  if (!list || Array !== list.constructor || list.length === 0){
    console.log('findMostRecentFileInList returning false');
    return false;
  }
  console.log('findMostRecentFileInList - returning', list.reverse().slice(1,2).toString());
  return list.reverse().slice(1,2).toString();
};

Full marks if you have already spotted the problem.

If not, no worries, allow me to explain.

We can disregard the vast majority of this function and just focus on two lines:

console.log(list.reverse().slice(1,2).toString());
return list.reverse().slice(1,2).toString();

What was confusing the heck out of me was that in the next then statement, the value I would receive would be incorrect. Yet the console log output only one step prior was definitely right.

Welp, the reason is as amusing as it is frustrating. It’s exactly the sort of thing that catches out many a developer (I would bet).

What happens here is that by calling list.reverse() in the console log statement, the list is correctly reversed.

The slice function takes the value I need and that’s correctly output to the screen.

So far, so good.

Then, on the very next line, I take the reversed list and reverse it again… putting it back into the original order. Then take a slice from that, and return that instead.

Oops.

It’s so obvious when it’s spelled out to you, but debugging that sort of thing is how devs like me lose tens of minutes, if not hours of time.

These sorts of things tend to catch me out late at night. Maybe I should work earlier in the mornings.

How I Fixed: Uncaught ReferenceError: dispatch is not defined

It’s always a fun time when you hit an error, and you google it, and there’s no #1 result for a StackOverflow post, where someone far smarter than I can ever hope to be has already encountered, resolved, and shared their fix with some other unfortunate soul.

You mean I have to engage my brain and think? World, you can be cruel.

Anyway, tonight’s error (or one of them) was this :

Uncaught ReferenceError: dispatch is not defined

It had me stumped for a while. This is a React app – based on a starter project. So, more than likely, this was my goof.

Anyway, I had myself some forethought and had followed the convention of adding PropTypes to the class I am working on.

See if you can spot the mistake:

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { myAction } from '../actions/someOfMyActions';

class MyClass extends Component {

  constructor(){
    super();
  }

  componentDidMount() {
    const { myAction } = this.props;
    dispatch(myAction('a','b'));
  }

  render() {
    // blah
  }

}

function mapStateToProps(state) {
  return {
    appState: state
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({
      myAction
    }, dispatch)
  };
}

MyClass.propTypes = {
  appState: PropTypes.object,
  loading : PropTypes.bool,
  items : PropTypes.array
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyClass);

Given that apparently, dispatch is not defined, I figured I would add it to the propTypes and see what kind of thing either was, or was not being passed in.

MyClass.propTypes = {
  appState: PropTypes.object,
  dispatch: PropTypes.function,
  loading : PropTypes.bool,
  items : PropTypes.array
};

That led to a new error. Which is good and bad.

Func, Not Function

It means what I did had some noticeable impact, but not the kind of impact that implies it’s resolved:

Warning: Failed prop type: MyClass: prop type `dispatch` is invalid; it must be a function, usually from React.PropTypes.
    in MyClass (created by Connect(MyClass))
    in Connect(MyClass)
    in Provider

Weird.

Looking back over the propTypes I suddenly remembered, it’s not function, it’s func. This caught me out last time.

The error could be nicer I guess.

MyClass.propTypes = {
  appState: PropTypes.object,
  dispatch: PropTypes.func,
  loading : PropTypes.bool,
  products : PropTypes.array
};

Updated, saved, and thanks to hot reloading, that error had gone before I’d tabbed back to my browser.

Cool.

But the problem wasn’t yet resolved. Actually, at this point I’d essentially made little progress in solving the problem.

I had confirmed dispatch was a function though:

Uncaught ReferenceError: dispatch is not defined;

Looking at the problem code again:

  componentDidMount() {
    const { myAction } = this.props;
    dispatch(myAction('a','b'));
  }

At this point I knew this was my boob for sure, and likely the error was staring me right in the face.

So, I did what any code goon would do, and I stuck in a console.log to figure out what the heck was on the props . In a second, you will see why this should have been obvious:

  componentDidMount() {
    const { myAction } = this.props;
    console.log('props', this.props);
    dispatch(myAction('a','b'));
  }

Which output a bunch of stuff which is quite hard to copy / paste in.

Anyway, it turned out on the props  was actions, which just so happened to contain the output from the function I had already declared:

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({
      myAction
    }, dispatch)
  };
}

doh!

RTFM Chris.

So I could update the call to:

  componentDidMount() {
    const { myAction } = this.props.actions;
    myAction('a','b');
  }

And what-do-you-know?! It worked!

Obvious, in hindsight.

By the way, I appreciate to any season React devs that this is likely a big “durrrr” moment.

Hopefully it saves someone a headache somewhere down the line.