Loading...

Follow The JavaScript Playground on Feedspot

Continue with Google
Continue with Facebook
or

Valid

React 16.8 introduced hooks; a new way to work with effects and state in React. No longer do React components that have state need to be ES2015 classes that extend React.Component - hooks let us write components as functions and still have all the functionality of class based components.

It’s important to note that React will continue to support class based components for a long time yet. It’s advised that you consider hooks going forward, but there’s no need to instigate a big migration of your code.

I wanted to get familiar with hooks and try them on some real life code, and this blog post is the result of doing that and writing down how I find it, and comparing the before and after code. This is far from a deep dive into hooks, but more a quick look at my first experience refactoring to use them. I hope you find it useful!

Although I’ve simplified the code for this example, I did really do this at work first on a real component that we shipped!

The component we are working with.

The component we’re going to refactor takes an id as a prop, and makes a request to an API to fetch data for the user with that given ID. Its id prop can change at any time, so we also have to fetch the user data again if the ID changes. Therefore we have componentDidMount and componentDidUpdate to deal with the first render and any subsequent prop changes. The render for this example just dumps the user data out, but in real life this would render a meaningful UI.

import React, { Component } from 'react'

export default class Demo extends Component {
  constructor(props) {
    super(props)

    this.state = {
      user: undefined,
    }
  }

  componentDidMount() {
    fetchUser(this.props.id).then(user => this.setState({ user }))
  }

  componentDidUpdate(prevProps) {
    if (this.props.id !== prevProps.id) {
      fetchUser(this.props.id).then(user => this.setState({ user }))
    }
  }

  render() {
    return (
      <pre>
        <code>{JSON.stringify(this.state.user, null, 4)}</code>
      </pre>
    )
  }
}

Don’t worry about the definition of fetchUser - it’s a small wrapper around fetch that talks to our API.

Refactoring to hooks

Let’s start thinking about how we will refactor this to use hooks. There are two hooks we’re going to use:

  • useState, which lets us hold a piece of state in our component. We’ll use this to hold the user data that we fetch from our API.
  • useEffect. This lets us run side effects in our components. That is, things that happen as a result of a React component being rendered. You can map this roughly onto the old React lifecycle methods - in fact the documentation says just that:

    If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

Because we’re using hooks, we will also rewrite our component as a function. So we can start with our shell:

import React, { useState, useEffect } from 'react'

const DemoWithHooks = props => {
  const [user, setUser] = useState(undefined)

  useEffect(() => {
    // TODO
  })

  return (
    <pre>
      <code>{JSON.stringify(user, null, 4)}</code>
    </pre>
  )
}

When we call useState we get back an array with two items in. The first is the actual value of the state, and the second is a function used to update that value. You can call these whatever you’d like, although the user and setUser style is becoming convention. We’re using ES2015 destructuring to keep the boilerplate down, but you could write it as:

const userState = useState(undefined)
const user = userState[0]
const setUser = userState[1]

The value passed to useState is the original value. This is needed for the first render. Here I’ve explicitly passed in undefined so it’s clear that when this component runs we don’t have a user yet. To get a user, we need to move on to the useEffect hook.

useEffect

useEffect takes a function and runs it when the component renders. This means it will run both when the component first mounts, and when the component is re-rendered. Don’t worry though, we are able to have control over exactly when it is executed, and we’ll see that shortly.

Let’s fill our useEffect call in with a function that fetches our user and updates the state. Note that we call setUser from within useEffect. This is common if you’ve got some state that you’re setting by making an HTTP request.

useEffect(() => {
  fetchUser(props.id).then(setUser)
})

When used in this manner, the function given to useEffect will be called:

  • when the component first renders
  • anytime the component is subsequently rendered

As it happens, for our component this is OK, because we only have one prop that could cause an update - id. And every time that property changes, we do want to fetch the user’s data again.

But, what if this component took many props, or had other bits of state? In that case, whenever any of those props changed, and the component was rendered again, our fetchUser code would run. It would do this even if props.id hadn’t changed, and that’s just a wasted network request if we already have the data for that user.

In a class based component we would tackle this by adding a conditional to our componentDidUpdate code:

componentDidUpdate(prevProps) {
  if (this.props.id !== prevProps.id) {
    fetchUser(this.props.id).then(user => this.setState({ user }))
  }
}

This ensures we only make the network request when the data we care about has changed. We can do the same with useEffect by passing a second argument which is an array of data that has to change for the effect to rerun:

useEffect(
  () => {
    fetchUser(props.id).then(setUser)
  },
  [props.id]
)

Now our effect will run on first render, and also whenever props.id changes. If any other data changes, it won’t trigger the effect.

The final component
const DemoWithHooks = props => {
  const [user, setUser] = useState(undefined)

  useEffect(
    () => {
      fetchUser(props.id).then(setUser)
    },
    [props.id]
  )

  return (
    <pre>
      <code>{JSON.stringify(user, null, 4)}</code>
    </pre>
  )
}

If you compare the code above to the starting component at the top of the post, I think it’s much cleaner. The first component has some near-duplicated code in the componentDidMount and componentDidUpdate, which is entirely removed as useEffect lets us express everything in one function. We also avoid the awkward comparison of props in componentDidUpdate; something that’s easy to get subtly wrong, especially in complex components, and cause bugs or pointless network requests. useEffect lets us define the effect and what should cause it to rerun really concisely.

If you’re using hooks, I also recommend the eslint-plugin-react-hooks package, which will give you handy linter errors or warnings for some common mistakes when using hooks. I’ve been finding it particularly useful for catching things I get slightly wrong as I adjust to using hooks over class based components.

If you’re not sure where to start with hooks in your codebase, I’d really recommend this approach of picking one straightforward component and refactoring it. It’s low risk, and a component with just one or two pieces of local state shouldn’t take long to refactor. It’s a great learning exercise and a good way of sharing knowledge of hooks across your team.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Whenever I’ve used TypeScript in the past, I’ve set up TSLint as my linting tool of choice. However, I’ve always wished I could use ESLint instead, for a few reasons:

  1. I am more familiar with ESLint, and I know its rules better and have my preferred set of plugins.
  2. All the JS projects I work on use ESLint, so having all my projects use the same linter is beneficial.
  3. I already have an ESLint plugin in my editor, so I don’t have to configure the TSLint plugin in addition.

I was therefore thrilled to read a post on the ESLint blog about the future of TypeScript and ESLint, with the TypeScript 2019 roadmap mentioning them transitioning to ESLint and contributing to the project.

I had to set up a new frontend project this week and I decided to use TypeScript and try ESLint for the first time. I thought it would be useful to document the process to help others get started!

Installing dependencies

First up, we’re going to need to install some packages. We’ll install eslint itself, but also two plugins we need to allow ESLint to lint TypeScript: a parser (so ESLint can understand TypeScript’s syntax) and the plugin (to enable linting on TS files):

yarn add --dev eslint
yarn add --dev @typescript-eslint/eslint-plugin
yarn add --dev @typescript-eslint/parser
Configuring ESLint

That gives us enough to set up ESLint. Let’s create a .eslintrc.js file and configure the parser and the plugin:

I much prefer using .eslintrc.js over a JSON file, primarily because it lets you leave comments in your configuration!

module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
}

With that ESLint is all set up to run on TS files, but we haven’t enabled any rules! You can find all the rules and documentation on GitHub, but I decided to enable the recommended set of rules that the plugin provides, by using the extends configuration key:

module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: ['plugin:@typescript-eslint/recommended'],
}

At the time of writing there isn’t a website with these rules documented yet, but I’m sure there will be soon, and I’ll update this post when that happens.

And with that, we’re set! The beauty of this is that you can continue to use any other ESLint configurations you like (for example, I always integrate Prettier into my ESLint setup) and now I can do that whilst also linting TypeScript, too!

Enabling ESLint on TS files in VSCode

One final note for all you VSCode users out there - by default the ESLint plugin only runs on javascript and javascriptreact files. To tell it to run on TS files, you need to update the eslint.validate setting to:

"eslint.validate": [
  "javascript",
  "javascriptreact",
  "typescript",
  "typescriptreact"
]

And that will get you nice linting errors in your editor.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

If you follow me on Twitter, or have read this blog for a while, you’ll probably know that I’m a big fan of Elm. It’s a functional, strictly typed language that compiles to JavaScript and is a great alternative to JavaScript for building web applications.

That said, it’s not the only contender in this space. Reason is also a very popular option that has gained a lot of traction recently. I’ve always been interested in trying it out, and Advent of Code, a series of coding challenges posted each day leading up to Christmas, gave me a great excuse.

If you’re into Elm, you might also be interested to know that I’ve done two videos completing Advent of Code challenges in Elm that you can find on Youtube.

If you’re eager to skip ahead into the code, you can find it all on GitHub. In the rest of this post I’ll talk you through my approach to getting up and running with Reason, and my thoughts on the language after trying it. I am not a Reason expert, so if you spot any errors or things I’ve misunderstood, please let me know! Equally, there might be better ways of solving the task, so if you have any suggestions please get in touch.

The first part of this blog post talks through my approach and how I solved the problem, and then we end with a list of my good and bad parts of trying Reason.

Getting started

I followed the official Installation and getting started guide to get easily up and running. It involved installing the compiler, BuckleScript, which is what takes Reason and produces JavaScript.

That let me run:

bsb -init my-new-project -theme basic-reason

To get a basic project up and running! I also installed reason-vscode so that I had nice error highlighting and type hinting as I coded. I find this particularly useful when working with a new language/framework that I’m not super familiar with.

Writing tests

I didn’t want to build a UI to solve the Advent of Code problem; so I did a bit of googling to see if I could use Reason to write some unit tests, and solve the problem in a TDD style. I managed to find bs-jest, a library that adds bindings to BuckleScript to the JS testing framework Jest. This lets us write Reason, but have it compiled into JavaScript that we can then run with Jest as normal. So we’ll write a tests.re file, have it compiled into tests.js, and then run jest tests.js. Setting this up was just a case of following the instructions in the README, and it worked perfectly.

The Advent of Code challenge

I was taking on Day Two, and for this exercise only completed Part One. I’ll leave Part Two as an exercise for you!

The first part of the exercise needed me to take a string, such as bababc, and calculate the frequencies that letters occur. So for this string, we’d end up with:

{ a: 2, b: 3, c: 1 }

So that was the first thing I set out to write. I discovered that BuckleScript provides a Js.Dict module that is the equivalent of a native JS object, and I could use that. It also provides Js.Array, and Js.String. Using a combination of methods from these modules, I could split my input, and loop over it, updating a dict with new frequencies as I go through each letter.

I decided to store the frequencies in a dictionary. In Reason you have to decide what the types of the values are in a dictionary, so I went with integers, given we’re counting frequencies.

I first set out to write a function that could take a dictionary and a letter, and update the frequency for that letter:

  • If the letter has no entry in the dictionary, create one and set the frequency to one.
  • If the letter has a frequency, update the count by one.

Defining this function looks very similar to JavaScript:

let incrementOrSetFrequency =
  (frequencies: Js.Dict.t(int), letter: string): Js.Dict.t(int) => {
};

The bit that Reason adds is the type annotations. After each of the two arguments, we declare the types. We don’t have to do this - Reason will be able to infer them for us - but I find it helps me work with code if I’ve documented the type, and very rarely the compiler can infer a type slightly differently to what you actually want it to be.

The type annotation above says that frequencies is a Js.Dict.t(int), which means a dictionary where each value is an int type. letter is a string. After the arguments we have the return type, which is also a dict, as we want to take the dict, update it, and then return it again.

The first thing we need to do is check to see if letter is in the dictionary, and we can use Js.Dict.get(frequencies, letter) to do this. It doesn’t return the value or undefined though, like you would expect in JavaScript. Instead, it returns something that’s an Option type. This is Reason’s way of trying to avoid unexpected undefined or nulls in your application. You can read more about Option on the Reason docs.

When you have a function that returns an Option type, you can use pattern matching to see what the value is, and act accordingly. So if we look in our dictionary for our letter and it returns None, we need to add the letter. If it returns Some(int), we want to increment it by one:

let incrementOrSetFrequency =
    (frequencies: Js.Dict.t(int), letter: string): Js.Dict.t(int) => {
  switch (Js.Dict.get(frequencies, letter)) {
  | Some(x) =>
    Js.Dict.set(frequencies, letter, x + 1);
    frequencies;
  | None =>
    Js.Dict.set(frequencies, letter, 1);
    frequencies;
  };
};
Getting our first test passing

At this point I decided I’d figured out enough Reason to be dangerous, and wanted to write a test so I could work towards getting it passing. I created __tests__/daytwo_test.re:

open Jest;
describe("DayTwo", () => {
  open Expect;
  test("letterFrequencies", () =>
    expect(DayTwo.letterFrequencies("bababc"))
    |> toEqual(Js.Dict.fromList([("b", 3), ("a", 2), ("c", 1)]))
  );

If you’ve written JS tests with Jest, you’ll probably find the above quite intuitive, and I was able to use Js.Dict.fromList to take a list of tuples and create the dictionary that I needed for the test. The compiler compiled this into a JS file that I could run using the regular Jest CLI. This was one thing I liked about Reason; I can use the regular Jest CLI, rather than having to use a special one specifically for Reason. Jest’s CLI is so good that it makes total sense to work on top of it rather than creating a language specific one from scratch.

To get the test passing we needed to take our input string, split it into a list of letters, and run each one through our incrementOrSetFrequency function:

let letterFrequencies = (input: string): Js.Dict.t(int) => {
  let frequencies = Js.Dict.empty();
  input
  |> Js.String.split("")
  |> Js.Array.reduce(
       (acc, currentValue) => incrementOrSetFrequency(acc, currentValue),
       frequencies,
     );
};

And with that the test is passing!

Getting frequencies for our entire puzzle input

Next we need to take our full puzzle input, which is a series of strings, and run the above function on each of them, so we can start to work towards the final answer that we need.

Once again, I start by writing a test. I replicate the input that the real puzzle provides by putting each entry on its own line. I want to make sure we get the logic for splitting lines works properly.

Note that {|string here|} allows us to define a multi-line string.

test("checksum", () => {
   let puzzleInput = {|
     abcdef
     bababc
     abbcde
     abcccd
     aabcdd
     abcdee
     ababab
   |};

   expect(DayTwo.checksum(puzzleInput)) |> toEqual(12);
});

We can use the familiar Js.String.split once again here, but pass it "\n" as the thing to split on. We then map the resulting lines over String.trim, which trims any whitespace and removes it. Note that we’re not using Js.String.trim here, this is the ReasonML module String, not the BuckleScript Js.String module. This was one of the things I found most confusing when learning Reason. It wasn’t clear why some of the functions we use are Reason modules, and others are provided by BuckleScript.

If you’re familiar with Reason and can clarify the above confusion, I’d love to talk it through and update the blog post to include it.

So, the first part of the checksum function is to take the multi-line input, split it, and then ensure that we don’t have any blanks:

let checksum = (input: string): int => {
  input
  |> Js.String.split("\n")
  |> Js.Array.map(String.trim)
  |> Js.Array.filter(s => String.length(s) > 0)
  // note: this is invalid (we're not returning an int)

Once I’ve split the lines and given them a trim, I then use Js.Array.filter to remove any strings that are entirely empty. Now we are working with an array of letter frequencies that looks something like this:

[
  "abcdef",
  "bababc",
  "abbcde",
  "abcccd",
  "aabcdd",
  "abcdee",
  "ababab",
]

So we want to take each one and pass it into the letterFrequencies function that we have defined:

let checksum = (input: string): int => {
  input
  |> Js.String.split("\n")
  |> Js.Array.map(String.trim)
  |> Js.Array.filter(s => String.length(s) > 0)
  |> Js.Array.map(letterFrequencies)
  // note: this is invalid (we're not returning an int)

Now we’ve turned that list of strings into a list of frequencies. This code sample highlights one of my favourite Reason features (I’m biased as it’s also a favourite feature of mine from other functional languages like Elm and Elixir), the pipeline operator. The pipeline operator takes the thing on the left and passes it as the last argument to the function on the right. It means fewer parentheses around everything and lends itself to creating really readable code.

Calculating frequency occurrences

Now we have a list of frequency dictionaries, we need to take them and figure out:

  • how many of them contain a letter exactly 3 times
  • how many of them contain a letter exactly 2 times

The result for each of those is what we’ll need to multiply together to get our checksum, which is the solution to our puzzle.

What I’d like to do is take our list of frequencies and map it into a list of Reason objects that contain two properties, twice and thrice. These will be booleans and correspond to if a word contains a letter twice or thrice. To help the compiler give me good type errors if I make a mistake, I create a custom type:

type twiceAndThriceFrequency = {
  twice: bool,
  thrice: bool,
};

This declares a type, twiceAndThriceFrequency, which is an object with two properties that are both booleans. I can then create a function that will take a frequencies dictionary and convert it into one of these objects. Now I have this custom type, I can use it in the type annotation too:

let findTwicesAndThrices = (frequencies: Js.Dict.t(int)): twiceAndThriceFrequency => {
  {twice: true, thrice: true }
};

For now I’ve hardcoded the values to both be true, we will fill those in shortly. Notice how having the custom type defined makes the type annotation read really nicely and clearly.

To figure out the value of the twice and thrice keys, we need to see if the frequencies dictionary has any values of 2 or 3 in it. For this problem, we don’t actually care about which letter occurs two or three times, we just need to know if any of them do.

We can use Js.Dict.values, which takes a dictionary and returns an array of the values inside it. It’s just like Object.values() in JavaScript. We can then use Js.Array.some, which takes an array and a function and tells us if any items in the array satisfy it. Therefore, we can define the functions hasTwices and hasThrices like so:

let hasTwices = (frequencies: Js.Dict.t(int)): bool => {
  frequencies |> Js.Dict.values |> Js.Array.some(v => v === 2);
};

let hasThrices = (frequencies: Js.Dict.t(int)): bool => {
  frequencies |> Js.Dict.values |> Js.Array.some(v => v === 3);
};

Note that in this solution I’m not worrying about performance. If I was, we’d be doing this differently to reduce the number of times we iterate over the frequencies array. I’ll leave it as an exercise to the reader to improve that.

Mapping to our twiceAndThriceFrequency type

Now we have these functions, we can define a function that will take a frequencies dictionary and return a twiceAndThriceFrequency type:

let findTwicesAndThrices = (frequencies: Js.Dict.t(int)): twiceAndThriceFrequency => {
  {twice: hasTwices(frequencies), thrice: hasThrices(frequencies)};
};

Notice that we don’t need the return keyword in Reason. The last expression in a function is automatically returned for you.

And once we have this function, we can update our main checksum function:

let checksum = (input: string): int => {
  input
  |> Js.String.split("\n")
  |> Js.Array.map(String.trim)
  |> Js.Array.filter(s => String.length(s) > 0)
  |> Js.Array.map(letterFrequencies)
  |> Js.Array.map(findTwicesAndThrices)
  // note: this is invalid (we're not returning an int)
Calculating our checksum

At this point we are working with a list of objects that have { twice: true/false, thrice: true/false } within them. We want to go through this list and reduce it down to two values: the number of times that we have a letter occurring twice, and the number of times we have a letter occurring three times. So if we have this list:

[
  { twice: true, thrice: false },
  { twice: false, thrice: false },
  { twice: true, thrice: true },
]

We want to end up with:

{ twice: 2, thrice: 1 }

It’s then these two numbers that we multiply to find our checksum.

We can use Js.Array.reduce to do this. It will take our array and loop through each value in turn, allowing us to check the values of twice and thrice and increment our accumulator accordingly. Our starting accumulator will be an object, which I also define a type for:

type twiceAndThriceCounter = {
  twice: int,
  thrice: int,
};

And now we can start planning our reduce call:

|> Js.Array.reduce(
  (acc: twiceAndThriceCounter, currentValue: twiceAndThriceFrequency) => acc
  {twice: 0, thrice: 0},
)

Inside the body of the callback function, we need to check the currentValue and check the values of twice and thrice.

This is a case where Reason’s pattern matching comes in really handy. We can write code that pattern matches against the object and its values:

switch (currentValue) {
  | {twice: true, thrice: true} => {
      twice: acc.twice + 1,
      thrice: acc.thrice + 1,
    }
  | {twice: true, thrice: false} => {
      twice: acc.twice + 1,
      thrice: acc.thrice,
    }
  | {twice: false, thrice: true} => {
      twice: acc.twice,
      thrice: acc.thrice + 1,
    }
  | {twice: false, thrice: false} => acc
},

Each case that we’re matching against starts with the pipe (|) and then we match against the twice and thrice values within currentValue. So the first will match only if currentValue has both values set to true, in which case we increment both of our counters. In the case of one of twice or thrice being true, we increment the appropriate counter and if both values are false, we do nothing.

Pattern matching is my favourite feature of Reason (it’s also one of my favourite parts of Elm), and it leads to some really nice, expressive code. What’s also nice is that if we don’t write code that deals with every possible case, we get a compiler error. In the example below, I’ve removed the case that deals with both values being true. You can see the compiler spot this and tell me:

  Warning number 8
  /Users/jackfranklin/git/advent-of-code/day-two-reason-ml/src/DayTwo.re 55:10-65:10

  53 ┆ |> Js.Array.reduce(
  54 ┆      (acc: twiceAndThriceCounter, currentValue: twiceAndThriceFrequenc
       y) =>
  55 ┆        switch (currentValue) {
  56 ┆        | {twice: true, thrice: false} => {
   . ┆ ...
  64 ┆        | {twice: false, thrice: false} => acc
  65 ┆        },
  66 ┆      {twice: 0, thrice: 0},
  67 ┆    )

  You forgot to handle a possible value here, for example:
{twice=true; thrice=true}

This means you can never end up with code in production that doesn’t deal with all possible cases, which is fantastic. It also means if you refactor and now your pattern matching is out of date, the compiler will tell you.

Once we have this reduce done, it’s going to end up turning our array of frequencies into one object with two values. The solution to the puzzle (and what we need to get our test passing) is to take these values and multiply them. We can do this by piping our object into an anonymous function that does just this:

|> result => result.twice * result.thrice

And with this, our tests are back to green!

 PASS  __tests__/daytwo_test.bs.js
  DayTwo
    ✓ letterFrequencies (6ms)
    ✓ checksum (1ms)

There’s one small refactor we can make here though. Much like JavaScript and its ES2015 destructuring, we can destructure an object into the keys when it’s passed into a function. So we can rewrite our final line as:

|> (({twice, thrice}) => twice * thrice)

Which I think reads a bit more clearly. And with that, our puzzle is solved!

Conclusion

This was literally the first time I’d written Reason and after finishing the Advent of Code challenge I took a moment to think through what I found good, and what I struggled with, from the perspective of a beginner using a new language.

It’s also worth noting that my experience with Elm almost certainly makes it easier for me to learn Reason, there are similarities between the two.

Things I liked
  • The tight interopability between Reason and JavaScript is very compelling. I could easily see myself writing one module in Reason in an existing JS application because the interop is so smooth and easy.
  • Continuing from the previous point, the fact that Reason can use Jest for its test runner is excellent. Not having to learn how to run another test runner was a major bonus. It also helps that Jest is absolutely exceptional and packs in a tonne of useful features, so it makes perfect sense that Reason would lean on that rather than build out a brand new test runner.
  • On the whole I found compiler errors clear and obvious. One of my main gripes with TypeScript is that some of the compiler messages were hard to parse, but Reason gave me understandable messages that I really appreciated, particularly as a beginner.
  • The documentation on the Reason site is excellent. Take this page on pattern matching as an example: it’s clear, the code samples are easy to follow, and it explains things thoroughly. It also avoids any complex jargon and doesn’t attempt to sound super clever.
  • This one is editor specific, but the reason-vscode plugin gives a really good developer experience. It was easy to quickly get formatting, syntax highlighting, compiler errors and so on in my editor. (If you use another editor, there are links to plugins on the Reason site).
  • Reason includes refmt, a code formatter for Reason code. Much like Prettier for JavaScript, this runs and formats your code. What’s great about this is that all Reason projects use this, so all Reason code is formatted the same, and that as a beginner any worries about conventions or how to format something are gone. I just run the formatter! The VSCode plugin runs this for me when I save, so I just didn’t have to think about it.
Things I found confusing

Please remember that I am writing this as a Reason beginner, not an authority! If I’ve misunderstood something or made a mistake, please let me know and I’d be happy to update the blog post and give credit accordingly.

  • I’ve struggled in my head to fully understand the iteraction between Reason, OCaml and BuckleScript. In my head Reason is a syntax on top of OCaml, and BuckleScript is the compiler that can produce JavaScript. I’m not sure if my mental model stacks up though, and I found it hard to get clarity on this online.
  • I also found it confusing where to look for documentation for available modules. For example, when wanting to split a string, I found the Str Reason module. However, this isn’t available when compiling with BuckleScript, so I ended up using the docs from the BuckleScript API for Js.String. After this I was confused as to which one I should use, and why some modules exist in BuckleScript, but others in Reason. This is still a big point of confusion for me - if you can help me understand it I’d love to chat and also update this blog post!
  • I think this is me being strongly biased based on my Elm experience, but I didn’t love that methods like Array.get may raise an exception if the item at the given index isn’t present. I think here I’m projecting my expectations from Elm onto Reason, and actually the approach Reason has taken probably is an easier entry point for JS programmers, but I’d rather they all return the Option type, which Reason does support and use

All in all, I’d really recommend giving Reason a go! I’m excited to see where the language and ecosystem goes in 2019 and beyond, and I’ll definitely be playing with it some more, maybe next time on an actual frontend project, rather than just a coding exercise.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

In the past year I’ve launched two video courses on React, and today I’m offering 40% off them over the Black Friday period.

You can use the coupon code JACKFRIDAY to take 40% off, and it works on both courses.

Buying the courses not only gets you access to the current content, but any updates to them forever, and I assure you that there’s updates planned in the near future, with some more testing content on its way.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

I’m sure that Kent needs no introduction, he’s a prolific contributor to the React community and ecosystem. One of the things he talks a lot about is testing, which just so happens to be one of my favourite topics, too!

In this hour long hangout, Kent and I compared our approaches, both where they align and where we have slightly different opinions. If you’re interested in hearing a deep dive on how to test React applications, this should really help. We mention different approaches, libraries and resources that have helped us get started with and improve our respective testing philosophies.

Don’t forget, if you are after some more testing resources, that my Testing React with Enzyme and Jest course is available now!

Testing React with Kent C. Dodds and Jack Franklin - YouTube
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Today I’m releasing my brand new video series titled “React in Five”

I’ve been working with, writing tutorials, and speaking about React for a few years now and something that I get asked fairly often is how to improve as a React developer.

The first answer is to spend time building React applications, but often people will miss out on the small tricks, tips, or lesser known parts of React that can make a big difference. That’s what this course is all about. Every video is less than five minutes long and covers a small part of React that you may or may not have come across, but will have an impact on how you build React applications.

The series is made up of ten videos, purposefully designed to be easily watchable on a commute, on a quick break from work or when you’ve got a spare five minutes over a weekend. The first four videos in the series are free and you can purchase the rest for $20.

PS: if you purchased the testing course, or you’re subscribed to the mailing list, keep an eye out for a little discount code heading your way.

By purchasing the videos you’ll also get access to all the source code, any updates over time and the ability to email me with questions about the course.

If this sounds interesting, you can watch the first video below, and head to the React in Five course page for the rest of the videos and to buy the full package.

React in 5: Fragments - YouTube
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

As mentioned in my last post on VSCode, I’ve recently been trialling it as my editor of choice and so far have found the experience to be excellent. Coupled with the amVim plugin, it’s really suited me well.

I know many people use VSCodeVim, but I was never able to get it running as smoothly as amVim.

One of the features that amVim doesn’t provide is gf, which in Vim means “go to file”. If your cursor was over a string, and you hit gf on the keyboard, Vim would try to go to that file.

Existing Plugins

I started searching for a plugin that might do this, and came across seito-openfile, which worked for most of my cases, but I really wanted one that I could customise more to work for me. In particular we use a lot of aliases on our large codebase at work, and I wanted to build a plugin that could support them.

I couldn’t quite find one that did exactly what I wanted, so I decided to bite the bullet and build one!

Presenting vscode-go-to-file

VSCode GoToFile is my attempt at recreating Vim’s gf functionality in VSCode. It will also parse aliases from your jsconfig.json, and is clever enough to try a few common extensions if the file path doesn’t have one (.js, .jsx, .css and .scss). Working on this plugin also enabled me to experience plugin development for the first time and I’ve been really impressed, VSCode offers a great API that is really well documented and a great tutorial for getting started.

Reporting issues

If you’d like to give this plugin a try, I’d be grateful for any feedback you may have. I’m sure there are many improvements to be made and I’d love you to open an issue if you find a problem.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

I have recently been trialling using Microsoft’s VSCode editor as my primary code editor, and so far I’ve been very happy with it. One feature that I’ve particularly enjoyed is “Go to Definition”. This lets you hover over any variable/class/object/etc and be taken to the place where it is defined, even if it’s in another file.

This is particularly useful for me in JavaScript imports. If I have this line:

import Foo from './foo'

I can right click on Foo (or hit the shortcut, F12 by default), and click “Go to Definition”, and be taken to foo.js.

One problem I found though is that by default, if the file is foo.jsx, not foo.js (at work we put React components in .jsx to differentiate them easily from plain JS files), this won’t work. We have Webpack configured to look for both .js and .jsx files, but need to tell VSCode to do the same.

The solution here is to define a jsconfig.json, which is a file that you can define to configure how VSCode understands your projects. We can tell VSCode that we’re working with JSX by adding "jsx": "react" to our jsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "jsx": "react"
  },
  "exclude": ["node_modules", "build"]
}

Note that exclude is important: here I’ve defined node_modules and also build, which is the directory that Webpack builds to. I’m doing this to stop VSCode wasting time trying to parse files in these directories.

Once you’ve updated this, you’ll find that “Go to Definition” works just fine on imports from .jsx files, as well as .js files.

Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview