Tuesday, 27 March 2018

React Code Style Guide

I've been having the time of my life with React lately. But on my journey, I’ve had a hard time finding good code style guidelines to keep the mix of JSX and JS clean and readable. I've been coming up with my own style guides that I'd love to share. Maybe these will be useful to you and, of course, feel free to share similar guidelines in the comment thread below.

Rule #1: Destructure your props

One of my favorite ES6 features is destructuring. It makes assigning object properties to variables feel like much less of a chore. Let's take a look at an example.

Say we have a dog that we want to display as a div with a class named after its breed. Inside the div is a sentence that notes the dog's color and tells us if it's a good dog or bad dog.

class Dog extends Component {
  render () {
    return <div className={this.props.breed}>My {this.props.color} dog is {this.props.isGoodBoy ? "good" : "bad"}</div>;
  }
}

That technically does everything we want, but it just seems like quite a big block of code for what really is only three variables and one HTML tag.

We can break it out by assigning all of the properties of props to local variables.

let breed = this.props.breed;
let color = this.props.color;
let isGoodBoy = this.props.isGoodBoy;

Using ES6, we can put it in one clean statement like this:

let { breed, color, isGoodBoy } = this.props;

To keep everything clean, we put our ternary operator (more on that later) in its own variable as well, and viola.

class Dog extends Component {
  render () {
    let { breed, color, isGoodBoy } = this.props;
    let identifier = isGoodBoy ? "good" : "bad";
    return <div className={breed}>My {color} dog is {identifier}</div>;
  }
}

Much easier to read.

Rule #2: One tag, one line

Now, we've all had that moment where we want to take our entire function and make it a mash of operators and tiny parameter names to make some uglified, superfast, unreadable utility function. However, when you're making a stateless Component in React, you can fairly easily do the same thing while remaining clean.

class Dog extends Component {
  render () {
    let { breed, color, goodOrBad } = this.props;
    return <div className={breed}>My {color} dog is {goodOrBad}</div>;
  }
}

vs.

let Dog = (breed, color, goodOrBad) => <div className={breed}>My {color} dog is {goodOrBad}</div>;

If all you're doing is making a basic element and placing properties in an HTML tag, then don't worry about making such a big deal of all the functions and wrappers to get an entirely separate class going. One line of code will do.

You can even get creative with some ES6 spread functions if you pass an object for your properties. Using this.props.content will automatically put the string between the open and close tag.

let propertiesList = {
  className: "my-favorite-component",
  id: "myFav",
  content: "Hello world!"
};
let SimpleDiv = props => <div {... props} />;

let jsxVersion = <SimpleDiv props={propertiesList} />;

When to use the spread function:

  • No ternary operators required
  • Only passing HTML tag attributes and content
  • Can be used repeatedly

When not to use the spread function:

  • Dynamic properties
  • Array or object properties are required
  • A render that would require nested tags

Rule #3: The rule of 3's

If you have three or more properties, then put them on their own line both in the instance and in the render function.

This would be fine to have just one line of properties:

class GalleryImage extends Component {
  render () {
    let { imgSrc, title } = this.props;
    return (
      <figure>
        <img src={imgSrc} alt={title} />
        <figcaption>
          <p>Title: {title}</p>
        </figcaption>
      </figure>
    );
  }
}

But consider this:

class GalleryImage extends Component {
  render () {
    let { imgSrc, title, artist, clas, thumbnail, breakpoint } = this.props;
    return (
      <figure className={clas}>
        <picture>
          <source media={`(min-width: ${breakpoint})`} srcset={imgSrc} />
          <img src={thumbnail} alt={title} />
        </picture>
        <figcaption>
          <p>Title: {title}</p>
          <p>Artist: {artist}</p>
        </figcaption>
      </figure>
    );
  }
}

Or the render:

<GalleryImage imgSrc="./src/img/vangogh2.jpg" title="Starry Night" artist="Van Gogh" clas="portrait" thumbnail="./src/img/thumb/vangogh2.gif" breakpoint={320} />

It can get to be too much of a codeblock to read. Drop each property to the next line for a clean, readable look:

let { imgSrc,
      title,
      artist,
      clas,
      thumbnail,
      breakpoint } = this.props;

and:

<GalleryImage
  imgSrc="./src/img/vangogh2.jpg"
  title="Starry Night"
  artist="Van Gogh" 
  clas="landscape"
  thumbnail="./src/img/thumb/vangogh2.gif"
  breakpoint={320} />

Rule #4: Too many properties?

Property management is tricky at any level, but with ES6 destructuring and React's state-based approach, there are quite a few ways to clean up the look of a lot of properties.

Let's say we're making a mapping application that has a list of saved addresses and a GPS coordinate for your current location.

The current user information of position and proximity to favorite address should be in the parent Component of App like this:

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      userLat: 0,
      userLon: 0,
      isNearFavoriteAddress: false
    };
  }
}

So, when we make an address and we want it to note how close you are to the address, we're passing at least two properties from App.

In App render ():

<Address
  ... // Information about the address
  currentLat={this.state.userLat}
  currentLong={this.state.userLon} />

In the render function for Address Component:

render () {
  let { houseNumber,
        streetName,
        streetDirection,
        city,
        state,
        zip,
        lat,
        lon,
        currentLat,
        currentLon } = this.props;
  return ( ... );
}

Already, you can see how this is getting unwieldy. If we take the two sets of information and break them out into their own objects, it becomes much more manageable.

In our App constructor ():

this.state = {
  userPos: {
    lat: 0,
    lon: 0
  },
  isNearFavoriteAddress: false
};

At some point before App render ():

let addressList = [];
addressList.push({
  houseNumber: "1234",
  streetName: "Street Rd",
  streetDirection: "N",
  city: "City",
  state: "ST",
  zip: "12345",
  lat: "019782309834",
  lon: "023845075757"
});

In App render ():

<Address addressInfo={addressList[0]} userPos={this.state.userPos} />

In the render function for Address Component

render () {
  let { addressInfo, userPos } = this.props;
  let { houseNumber,
        streetName,
        streetDirection,
        city,
        state,
        zip,
        lat,
        lon } = addressInfo;
  return ( ... );
}

Much, much cleaner. React also has some great ways to ensure that object properties exist and are of a certain type using PropTypes that we don't normally have in JavaScript, which is just a great OOP thing anyway.

Rule #5: Dynamic renders - Mapping out arrays

Quite often in HTML, we're writing the same basic pieces of code over and over, just with a few key distinctions. This is why React was created in the first place. You make an object with properties that return a complex, dynamic HTML block, without having to write each part of it repeatedly.

JavaScript already has a great way to do lists of like information: arrays!

React uses the .map() function to lay out arrays in order, using one parameter from the arrays as a key.

render () {
  let pokemon = [ "Pikachu", "Squirtle", "Bulbasaur", "Charizard" ];
  return (
    <ul>
      {pokemon.map(name => <li key={name}>{name}</li>)}
    </ul>
  );
}

You can even use our handy-dandy spread functions to throw a whole list of parameters in by an object using Object.keys() (keeping in mind that we still need a key).

render () {
  let pokemon = {
    "Pikachu": {
      type: "Electric",
      level: 10
    },
    "Squirtle": {
      type: "Water",
      level: 10
    },
    "Bulbasaur": {
      type: "Grass",
      level: 10
    },
    "Charizard": {
      type: "Fire",
      level: 10
    }
  };
  return (
    <ul>
      {Object.keys(pokemon).map(name => <Pokemon key={name} {... pokemon[name]} />)}
    </ul>
  );
}

Rule #6: Dynamic renders - React ternary operators

In React, you can use operators to do a conditional render just like a variable declaration. In Rule #1, we looked at this for stating whether our dog was good or bad. It's not entirely necessary to create an entire line of code to decide a one-word difference in a sentence, but when it gets to be large code blocks, it's difficult to find those little ?'s and :'s.

class SearchResult extends Component {
  render () {
    let { results } = this.props;
    return (
      <section className="search-results">
        {results.length > 0 &&
          results.map(index => <Result key={index} {... results[index] />)
        }
        {results.length === 0 &&
          <div className="no-results">No results</div>
        }
      </section>
    );
  }
}

Or, in true ternary fashion

class SearchResult extends Component {
  render () {
    let { results } = this.props;
    return (
      <section className="search-results">
        {results.length > 0
          ? results.map(index => <Result key={index} {... results[index] />)
          : <div className="no-results">No results</div>
        }
      </section>
    );
  }
}

Even with our tidy result mapping, you can see how the brackets are already nesting quite densely. Now, imagine if our render had more than just one line. It can pretty quickly get unreadable. Consider an alternative:

class SearchResult extends Component {
  render () {
    let { results } = this.props;
    let outputJSX;
    if (results.length > 0) {
      outputJSX = (
        <Fragment>
          {results.map(index => <Result key={index} {... results[index] />)}
        </Fragment>
      );
    } else {
      outputJSX = <div className="no-results">No results</div>;
    }
    return <section className="search-results">{output}</section>;
  }
}

Ultimately, the code length is about the same, but there is one key distinction: with the first example, we're rapidly switching back and forth between two different syntaxes, making visual parsing taxing and difficult, whereas the second is simply plain JavaScript with value assignments in one, consistent language and a one-line function return in another.

The rule of thumb in this situation is that if the JavaScript you're putting into your JSX object is more than two words (e.g. object.property), it should be done before the return call.

Wrap up

The combination of syntax can get messy, and these are the most obvious situations where I saw my code going off the rails. Here are the basic concepts that these all come from and can be applied to any situation that wasn’t covered here:

  • Use ES6 features. Seriously. There are a lot of fantastic features that can make your job easier, faster, and much less manual.
  • Only write JSX on the right side of an = or a return.
  • Sometimes you need JavaScript in your JSX. If your JavaScript doesn’t fit on one line (like a .map() function or ternary operator), then it should be done beforehand.
  • If your code starts looking like (<{`${()}`} />), then you’ve probably gone too far. Take the lowest level outside the current statement and do it before this one.

The post React Code Style Guide appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2ut6qA2
via IFTTT

No comments:

Post a Comment

Passkeys: What the Heck and Why?

These things called  passkeys  sure are making the rounds these days. They were a main attraction at  W3C TPAC 2022 , gained support in  Saf...