Tag Archive

Tag Archives for " javascript "

Add Hooks to Class Components With Higher-Order Components

If you are using class components, but want to use hooks, you can’t do so directly. One strategy for adding them is to use adapter components. Another strategy is to use higher-order components to pass along data from hooks as props.

Example: Creating a MessageStore

Here’s our sample custom hook: We want to build a flash messaging system, similar to what’s provided by Ruby on Rails.

const useMessageStore = () => {
  const messageReducer = (state, action) => {
  switch (action.type) {
    case 'ADD':
      return [
        ...state,
        action.payload,
      ]
    case 'CLEAR':
      return []
    case 'DISMISS':
      return state.filter((message, index) => index !== action.payload)
    default:
      return state
  }
}
  const [state, dispatch] = useReducer(messageReducer, [])
  return [state, dispatch]
}

Using The Hook in A Functional Component

If we want to display or write messages to our queue from any functional component, we can do so by calling this hook:

const MyMessagingComponent = () => {
  const [messageStore, messageDispatch] = useMessageStore()
  return messageStore.map(message => <span>message.text</span>)
}

And we want to add a message from a function component, we can do it like this:

const MyButton = () => {
  const [messageStore, messageDispatch] = useMessageStore()
  const sendClickMessage = () => { 
    messageDispatch({ type: 'ADD', payload: 'Clicked the button'})
  }
  return (<button onClick={sendClickMessage}>Click Me!</button>)
}

Creating a HOC With Our Hook

Alternatively, we could create a component that passes the data from the hook along:

const withMessageStore = (WrappedComponent) => (props) => {
  const { state, dispatch } = useContext(MessageContext)
  return (<WrappedComponent
    {...props}
    messageStore={state}
    messageDispatch={dispatch}
  />)
}

Apply the HOC to Class Components

Using this method, we can now use our hooks in existing code, without having to refactor the whole thing:

class OldStodgyComponent extends React.Component {
  render() {
    return this.props.messageStore.map(message => <span>message.text</span>)
  }
}

export default withMessageStore(OldStodgyComponent)

Redux Now Has Hooks. A Before and After Comparison

Today the react-redux team released version 7.1.0, which adds hooks to react-redux! Here’s a quick comparison of how it could change how you write components.

First, A Brief Overview of The New Toys

  • useSelector: Pass in a function that takes the state as an argument and returns a value. Used to get a single value from state. Can act as a replacement for mapStateToProps.
  • useDispatch: returns a reference to the dispatch object. It can act as a replacement for mapDispatchToProps.
  • useStore: returns an instance of the store. Generally not recommended.

Old Example: A Search Form

An example component that stores a query and when a form is submitted to search. I wanted to keep the example simple, so use your imagination for the part where it fetches results.

import React from 'react'
import { connect } from 'react-redux'

const defaultSearchBar = ({ query, updateQuery, handleSearch }) => {
  const handleSubmit = (e) => {
    e.preventDefault()
    handleSearch(query)
  }

  const handleChange = e => updateQuery(e.target.value)
  return (
    <form onSubmit={handleSubmit}>
      <input
        name="search"
        value={query}
        onChange={handleChange}
      />
    </form>
  )
}

const mapStateToProps = state => ({
  query: state.query,
})

const mapDispatchToProps = dispatch => ({
  updateQuery: newQuery => dispatch({ type: 'UPDATE_QUERY', payload: newQuery }),
  handleSearch: newSearch => dispatch({ type: 'NEW_SEARCH', payload: newSearch }),
})

const connectedSearchBar = connect(
  mapStateToProps,
  mapDispatchToProps,
)(defaultSearchBar)

The New Component

In our new example, we have a few differences: We eliminate the connect function, mapStateToProps, and mapDispatchToProps entirely. This means our component no longer takes in props directly. Now, our form looks like this:

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'

const hookedSearchBar = () => {
  const dispatch = useDispatch()
  const query = useSelector(state => state.query)
  const handleSubmit = (e) => {
    e.preventDefault()
    dispatch({ type: 'NEW_SEARCH', payload: query })
  }
  const handleChange = e => dispatch({ type: 'UPDATE_QUERY', payload: e.target.value })

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="search"
        value={query}
        onChange={handleChange}
      />
    </form>
  )
}

Creating Your Own Custom Hooks

If you have code that gets shared frequently between components, you can create a custom hook to keep all of that functionality together. Here’s an example of us isolating the redux-specific part of our form into its own hook:

useSearchQuery = () => {
  const dispatch = useDispatch()
  const query = useSelector(state => state.query)
  const updateQuery = query => dispatch({ type: 'UPDATE_QUERY', payload: query })
  const updateSearch = search => dispatch({ type: 'NEW_SEARCH', payload: search })
  return { query, updateQuery, updateSearch }
}

Should You Make The Switch?

The ability to create redux hooks above is interesting, but I am also concerned that it could make code harder to test, as testing these components is already dead simple. I’m not sold either way, but I hope this comparison makes it easier for you to make informed decisions about your code base.

How to Use useEffect (and other hooks) in Class Components

Hooks are a great new feature in React. The first initial case I found them useful was where we had to create class components just because we wanted to use a single ref or store one variable in state. Now in those cases, we can use hooks to write more succinct code. Here’s a quick example using useState :

Using useState

Old and Busted

class SearchBar extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      query: ''
    }
  }

  render() {
    return (
      <form action="https://duckduckgo.com">
        <input
          type="text"
          name="q"
          onChange={(e) => { this.setState({ query: e.target.value }) }}
        />
        <input type="submit" value="search" />
      </form>
    )
  }
}

New Hotness

const SearchBar = () => {
  const [query, setQuery] = useState('')
  return (
    <form action="https://duckduckgo.com" >
      <input
        type="text"
        name="q"
        onChange={(e) => { setQuery(e.target.value) }}
      />
      <input type="submit" value="search" />
    </form>
  )
}

Thinking in Effects

useRef is similar. However, working with useEffectis a bit different. It’s designed to replace several lifecycle methods, such as componentWillReceiveProps, componentWillMount, and componentWillUnmount. It doesn’t map one-to-one to old functionality like state and ref, which makes it more difficult to “think in effects.”

Here’s what finally made it click for me: the first two arguments of useEffect are a function (didUpdate), and an array of dependencies. the didUpdate function can return a function of its own, a cleanUp function. When a component mounts or the dependencies are updated, didUpdate is called. When the component unmounts, cleanUp is called if present.

Once you grok how effects work (“when this variable changes, do something”) over the lifecycle methods, you can save yourself a lot of headaches in code. You no longer have to write code like this:

Old and Busted: componentWillReceiveProps

  componentWillReceiveProps = (nextProps) => {
    if (nextProps.position !== this.props.position) {
      this.moveMap(nextProps.position)
    }
  }

You can now write more succicnt statements like this:

New Hotness: useEffect

useEffect(() => { moveMap(position) }, [position])

Here’s another example is using useEffect to replace componentDidMount and componentWillUnmount for setting and clearing event listeners. By declaring the dependencies array as empty, you only call the didUpdate and cleanUp functions once each. No dependencies mean no updates.

Old and Busted: componentWill(un)mount

  componentWillMount = () => {
    /* attach listeners to google StreetView */
    const streetView = this.getStreetView()
    window.google.maps.event.addListener(streetView, 'zoomChanged', this.handlePovChanged())
  }

  componentWillUnmount = () => {
    window.google.maps.event.clearInstanceListeners()
  }

  getStreetView = () => { /* ... */ }
  handlePovChanged = () => { /* ... */ }

New Hotness: useEffect

  const getStreetView = () => { /* ... */ }
  const handlePovChanged = () => { /* ... */ }
  const { addListener, clearInstanceListeners } = window.google.maps.event
  
  useEffect(() => {
    const streetView = getStreetView()
    addListener(streetView, 'on', handlePovChanged())
    return clearInstanceListeners
  }, []) // empty dependency array = only called on mount and unmount

Instead of grouping functionality by when they are in the lifecycle, you can group them by concern. It makes your code easier to reason about.

There’s one problem. You can’t use useEffect (or any other hook) in a class component. Hooks are only available in functional components. If you want to refactor your lifecycle methods to use useEffect, you have to refactor entire class components writ large. This is both time-consuming and prone to error. What if you could refactor just this one part of the code?

Use Hooks With Adapter Components

Considering that:

  • we cannot use hooks within class components…
  • we can use hooks within functional components…
  • And we can use functional components within class components…

We can see a solution: create a functional component that encapsulates the useEffect behavior, and use that in your class components! It’s a take on the adapter pattern from object-oriented programming: We create a wrapper that encapsulates the functionality of a piece of code (useEffect), while changing its interface. A hook in component’s clothing. 🐺

Here’s a simple one I use to replace componentWillReceiveProps checks like the one above.

Observer: useEffect Adapter Component

const observer = ({ value, didUpdate }) => {
  useEffect(() => {
    didUpdate(value)
  }, [value])
  return null // component does not render anything
}

Example Usage

<Observer value={this.props.position} didUpdate={this.moveMap} />

You don’t have to pass the argument to didUpdate, but in this case I found that the easiest way to have access to that variable. You could also create a similar component to handle mounting and unmounting behavior.

MountHandler: another useEffect Adapter

const mountHandler = ({ onMount, onUnMount }) => {
  useEffect(() => {
    onMount()
    return onUnMount
  },[])
  return null
}

You could combine these into one component, or create more specific adapters that encase more business logic themselves. Do what works best for your codebase. Ideally, these a stop-gap solution that help you refactor class-based components incrementally. Here’s the strategy I used:

  1. Identify a class-based component you want to refactor.
  2. Isolate part of the class-specific code.
  3. Create an adapter component that allows you to remove that class specific code (for example, lifecycle methods)
  4. Run tests, ensure that all functionality still works.
  5. Repeat until you have removed all class-specific code.
  6. Convert the component from a class to a function.

In the end, You end up with code thats easier to reason about and more performant. Hope this helps!

Test Clicks On Connected Components In Under 10 Lines of Code

Here’s a fairly benign component, that can give developers pause when its time to write unit tests for your components: 

const ClickableButton = props => (
  <button onClick={props.doSomething}>Click Me!</button>
)

const mapDispatchToProps () => ({
  doSomething: dispatch(someFancyAction())
})

export default connect(
  null, 
  mapDispatchToProps,
)(ClickableButton)

There is only thing worth testing here: That when we click the button, the function we passed in as a prop gets called. That prop function could be a complex chain of actions & API calls. You don’t want to stress about that, at least not in these tests.  But to do this, are we going to have to create mock store and a provider component just because it’s connected? Ugh!

There has to be a better way. 

You Can Remove The Redux Connection Entirely

While you want your component to be the default export, you can export the unconnected component, and just test that! Hat tip to Dave Ceddia for show me a better way to export a connected component.  All you have to do is change one line: 

export const ClickableButton = props => (

As an additional trick, if you have any helper functions not attached to the component, you can export those as well for easy testing. 

With Jest and Enzyme, The Rest is Easy

Inside our test, import the unconnected component. Then, you can create a mock function using Jest, and simulate the click using Enzyme. Here’s what the test looks like all together: 

describe('<ClickableButton />', () => {
  it('calls the doThing prop when the button is clicked', () => {
    const props = { doSomething: jest.fn() }
    const wrapper = shallow(<ClickableButton {...props} />)
    wrapper.find("button").first().simulate("click")
    expect(props.doSomething).toHaveBeenCalled()
  })
})

Write Redux Reducer Tests Fast

Redux may come with a lot of boilerplate, patterns, and libraries, but at its core it’s simple.  A current state and an action go in, new state comes out.

Just because the code is simple doesn’t mean it shouldn’t be tested. If you are using Redux in your application, that means your store is a core part of it. For that reason, you should have tests for every action your reducer could take, and every logic branch that they could take. But don’t fret! Since reducers aren’t complicated, neither is writing tests. With a little setup, you can follow this pattern and knock out reducer tests like a pro. 

Setting Up For Reducer Tests

The only setup I use is to use the startState object if I need to have an initials state for every test. Unlike testing thunks, no mock stores necessary. Our initial state (and states we use in testing) will be plain objects. These tests should taste like vanilla.

const startState = {} // initial state shape if needed

The Reducer We’ll Be Testing

I’ll pull the reducer example from an earlier tutorial about creating asynchronous actions. Code reuse, woohoo! 🎉

const postReducer = (state = {}, action) => {
  switch (action.type) {
    case types.LOAD_POST_REQUEST:
      return {
        ...state,
        posts_loading: true,
      }
      case types.LOAD_POST_SUCCESS:
        return {
          ...state,
          posts_loading: false,
          posts: action.payload,
        }
        case types.LOAD_POST_FAILURE:
        return {
          ...state,
          posts_loading: false,
          posts_error: action.payload,
        }
        //...other actions
        default:
           return state 
        }
    }
}

And for quick reference, here are the action creators you can use to work with this reducer. We’ll need them shortly: 

const loadPostsRequest = () => ({ type: types.LOAD_POSTS_REQUEST })

const loadPostsSuccess = posts => ({
  type: types.LOAD_POSTS_SUCCESS,
  payload: posts,
})

const loadPostsFailure = error => ({
  type: types.LOAD_POSTS_FAILURE,
  payload: error,
  error: true,
})

export default {
  loadPostsRequest,
  loadPostsSuccess,
  loadPostsFailure,
}

The Reducer Test Pattern

Every test I write for a reducer follows this pattern: 

  1. I declare an initial state
  2. I declare an expected result state
  3. I create an action
  4. I call the reducer with the action and the initial state
  5. I compare the actual and expected state where I expect changes. 

Here’s the template, in code form: 

it('should apply the updates as expected', () => {
  const start = { ...startState } // add or change fields as needed.
  const expected = {} // expected result state
  const action = actions.myActionCreator() //include arguments as needed
  const actual = reducer(start, action) 
  expect(actual).toEqual(expected)
})

Boom. done.  To keep things even simpler, if your application doesn’t have an initial state, you can declare start from scratch. As you’ll see below, you will want to tweak the formula for specific cases, but they will all follow this template. 

Example 1: LOAD_POSTS_REQUEST

Let’s see it in action.  All our first action is responsible for is toggling a boolean value. Notice in this example, I’m not going to create an expected result state. Since we are only interested in one boolean, we can look at that value, and use Jest’s toBeTruthy() and toBeFalsy() matchers. If you’re not familiar with all of the matchers, here’s a quick list for reference. 

describe('LOAD_POSTS_REQUEST', () => {
  it('marks the current task as not loaded', () => {
    const start = {
        ...startState,
        posts_loading: false,
      }
    const action = actions.loadPostsRequest()
    const actual = reducer(start, action).posts_loading
    expect(actual).toBeTruthy()
  })
})

Example 2: LOAD_POSTS_SUCCESS

Here we’ll want to write two tests: one to confirm we load the posts into state, and one to confirm we have marked that the posts are no longer in a loading state.  Because of this, we can move some of our setup code into a before function.

describe('LOAD_POSTS_SUCCESS', () => {
  let actual
  let expected
  beforeEach(() => {
    const start = {
      ...startState,
      posts: [],
      posts_loading: true
    }
    expected = ['some', 'posts']
    const action = actions.loadPostsSuccess(expected)
    actual = reducer(start, action)
  })

  it('marks posts as loaded', () => {
    expect(actual.posts_loading).toBeFalsy()
  })
  it('saves posts in state', () => {
    expect(actual.posts).toEqual(expected)
  })
})

Example 3: LOAD_POSTS_FAILURE

Similar to our thunk example, our failure use case looks similar to our success case. Still, it’s good to be thorough. Few things are as frustrating as expecting a useful error message and instead finding nothing. 

describe('LOAD_POSTS_FAILURE', () => {
  let actual
  let expected
  beforeEach(() => {
    const start = {
      ...startState,
      posts_error: null,
      posts_loading: true
    }
    expected = 'Posts not found!'
    const action = actions.loadPostsFailure(expected)
    actual = reducer(start, action)
  })

  it('marks posts as loaded', () => {
    expect(actual.posts_loading).toBeFalsy()
  })
  it('saves posts error in state', () => {
    expect(actual.posts_error).toEqual(expected)
  })
})

Apply This To Your Codebase

If there are errors in how your reducer updates state, it can be difficult to debug. While the Redux DevTools help, wouldn’t it be better if those bugs never even made it to the browser? To help prevent them from escaping, make sure your reducers are thoroughly tested. The pattern can easily adjust to other common reducer use cases: 

  • Have conditional logic in your reducer? Write a test for each logic branch. 
  • Have validation in your reducer? Throw valid and invalid actions at it, to make sure it handles both cases properly. 
  • Transforming data within your reducer? Adjust the expected call to ensure the data comes out shaped just how you want. 

Still have a particular action that you are having a difficult time with? It could be a sign that you have a messy or overly complex action or state shape, and some refactoring may be in order. 

How to Test Async Redux Thunks

In a previous post, you learned how to make HTTP requests inside your redux application. We use redux-thunk, a library that enables you to dispatch functions in addition to flux-style actions. With it, you can dispatch functions to handle more complex cases such as asynchronous operations. But then how do you test them? Testing can be more work than writing the functioning code itself. Dealing with server responses and timing was hard enough as it is. Luckily, there are tools and patterns you can apply to work, and make your codebase more reliable with ease.

First, we’ll take a look at the tools that we will be using for testing. Then, how to apply them to our operation. 

Tools of the Testing Trade

  • Jest – Jest is a JavaScript testing library from the Facebook development ecosystem, just like React. It’s designed to require no configuration and get out of your way you write tests easier and faster. 
  • Redux-mock-store – Since the primary goal of the action is to update a redux store, you will need a way to mock the redux store. redux-mock-store does just that.
  • Moxios – Moxios is a Javascript library that stubs out Axios requests. We’ll use this to decouple our code from the server so we can isolate our logic and test only

Quick Review: Our HTTP Action

Here’s the thunk from the previous tutorial: 

const fetchPosts = () => {
  const url = '/our-app/posts.json'
  return (dispatch) => {
    dispatch(actions.loadPostsRequest())
    axios.get(url)
      .then((response) => {
        dispatch(actions.loadPostsSuccess(response.data))
      })
      .catch((error) => {
        dispatch(actions.loadTaskHistoryFailure(error))
      })
  }
}

Now, let’s get to work on adding some tests to this code, so that we can make changes to code base without fear of causing a regression.

1. Create a Mock Store

First, we’ll set up our store. Since our redux application uses the thunk middleware, we’ll also need to apply that middleware when testing. Once we’ve done that we’ll create a function to help us set up our state for tests. Many applications have some kind of an initial state. Instead of creating that for every test, instead, we’ll create a helper function that takes a configured store, and combines the initial state with the state you pass as an argument.

import thunk from 'redux-thunk'
import configureMockStore from 'redux-mock-store'

export const startState = {} //put initial state here

export const mockStore = configureMockStore([thunk])

export const makeMockStore = (state = {}) => { 
  return mockStore({
    ...startState,
    ...state,
  })
}

2. Create Some Moxios Helpers

Next, let’s create a couple of helper functions for moxios. Axios & Moxios look at the status code to determine whether or not to resolve or reject the promise. These two functions will save us a bit of time when writing multiple API tests. These helper functions will save you quite a few keystrokes if your application has a lot of different HTTP-based thunks.

const mockSuccess = data => ({ status: 200, response: { data } })
const mockError = error => ({ status: 500, response: error })

3. Configure Setup and Teardown for Your Tests

For our tests, we’ll need to set up and tear down the Moxios adapter. It intercepts outgoing HTTP requests, allowing you to control the response the function you are testing gets back.  Here’s what that looks like: 

describe('fetchPosts', () => {
  beforeEach(() => moxios.install())
  afterEach(() => moxios.uninstall())
})

4. Write Your On Success Test

What do we want to assert here?

You aren’t testing any of the server-side logic. You aren’t testing that state changed because that’s the reducer’s job. You should write separate reducer tests for that. The thunk is only responsible for deciding which actions to dispatch, so that’s what to focus on.

So the jobs our test needs to accomplish are:

  1. create a mock instance of the store. You’ll be dispatching actions to it. 
  2. create a mock server response. 
  3. call your thunk, and assert that it dispatched the correct actions to your mock store.

Altogether, it looks like this. 

  it('dispatches loadPostsSuccess with server data on success', () => {
    const response = ['some', 'posts']
    const store = makeMockStore()
    moxios.wait(() => {
      const request = moxios.requests.mostRecent()
      request.respondWith(mockSuccess(response))
    })

    const expected = [
      actions.loadPostsRequest(),
      actions.loadPostsSuccess(response),
    ]

    store.dispatch(fetchPosts()).then(() => {
      const actual = store.getActions()
      expect(actual).toEqual(expected)
    })
  })

5. Now do the Same for the Error Response

Don’t just test the happy path. When writing tests it’s prudent to ask yourself, “what could go wrong?” Our server could throw an error response, so we want to test for that use case as well. In our example, the error test case looks almost identical to our success test case. 

  it('dispatches loadPostsError with server data on success', () => {
    const response = 'error message'
    const store = makeMockStore()
    moxios.wait(() => {
      const request = moxios.requests.mostRecent()
      request.respondWith(mockError(response))
    })

    const expected = [
      actions.loadPostsRequest(),
      actions.loadPostsError(response),
    ]

    store.dispatch(fetchPosts()).then(() => {
      const actual = store.getActions()
      expect(actual).toEqual(expected)
    })
  })

Apply This To Your Applications

This is the purest example of how to test asynchronous operations in your application. Of course in the real world, it’s never quite that simple. If there are additional use cases that you can think of, be sure to write tests for those as well. For example, are there different kinds of successful or error responses you could expect from the server? Do you need additional logic to handle them? If so, it could be a use case for creating additional tests. 

Think through your different use cases and decide the best approach.

How to Perform HTTP Requests with React & Redux

Async is one of the toughest problems in front-end development. It’s one of the reasons Redux and React were created. React all started when Facebook had what seemed like a trivial problem: Sometimes, the “unread messages” count in the header and the footer of the page would be different. This Skinner box is so important to Facebook’s business model, they decided to build a whole framework around it. By managing all changes in a global state, and rendering components based off of that state exclusively, you eliminate these kinds of problems. 

Most Async requests come from talking back and forth with the server. Let’s look at how we can make updates to our Redux state with HTTP requests.

First, Installing the Middleware.

Redux doesn’t come with a way to handle this out of the box.  The typical model in Redux is that you call the dispatch function, passing in an action as an argument. The dispatch function gives that action to the reducer, which goes up to update the state. All of these are synchronous actions. What if we want to dispatch asynchronous actions? For that, we’ll be using middleware called “redux-thunk.” redux-thunk gives you the ability to dispatch functions or actions. These functions can then dispatch actions themselves, but more on that later. First, install the middleware:

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'

const initial state = {
  posts_loading: false,
  posts: [],
  posts_error: null,
}

const configureStore = () => createStore(
  reducer,
  initialState,
  applyMiddleware(thunk)),
)

export default configureStore

 A Couple Quick Thunk Examples

A thunk is a special kind of action creator that returns a function. The function receives two arguments: dispatch and getState, which unsurprisingly is a function that returns the state. That’s another benefit of using thunk: it allows us to fire dispatches based on the current state, without passing in any arguments. Here are some examples:

const slowDispatch = () => {
  return (dispatch, getState) => {
     return setTimeout(() =>
       dispatch(increment()), 1000)
     )
  )
}

const maybeDispatch = () => {
  return (dispatch, getState) => {
    if (getState().allowIncrement) dispatch(increment())
  }
}

// If you want to be terser, you can write these as one-liners

const slowDispatch = () => (dispatch) => setTimeout(() => dispatch(increment()),1000)

const maybeDispatch = () => (dispatch, getState) => getState().allowIncrement ? dispatch(increment()) : null

Create the actions & action creators.

aka good old Redux boilerplate. We’ll be following the ducks pattern for this exercise.

First, there are three actions, one that will tell us when the request started, one for handling success, and one for handling errors. We’ll create types for these. You could just use the strings instead of declaring constants, but this strategy helps you more quickly identify typos when debugging. A mistyped action will throw an error instead of failing silently.

// types.js
const LOAD_POSTS_REQUEST = 'tasks/history/request'
const LOAD_POSTS_SUCCESS = 'tasks/history/success'
const LOAD_POSTS_FAILURE = 'tasks/history/failure'

export default { 
  LOAD_POSTS_REQUEST,
  LOAD_POSTS_SUCCESS,
  LOAD_POSTS_FAILURE,
}

Then, we’ll create our action creators. Again, we could do this inside of our thunk, but this helps keep the code clean. You can also use these when writing tests, and they will help you write them more efficiently.  We’ll create three: one to update the state when we are loading, one when we get a successful response, and one when we get an error.

import types from './types'

const loadPostsRequest = () => ({ type: types.LOAD_POSTS_REQUEST })

const loadPostsSuccess = posts => ({
  type: types.LOAD_POSTS_SUCCESS,
  payload: posts,
})

const loadPostsFailure = error => ({
  type: types.LOAD_POSTS_FAILURE,
  payload: error,
  error: true,
})

export default {
  loadPostsRequest,
  loadPostsSuccess,
  loadPostsFailure,
}

Updating Our Reducer

Now that we have actions, we need to handle them in our reducer. We’ll store three variables. First, a boolean to track the loading state. We can use this to toggle loading indicators in our interface. We’ll also store the results in an array, and store the error we get in response if there is a problem.

port types from './types'

const postReducer = (state = {}, action) => {
  switch (action.type) {
    case types.LOAD_POST_REQUEST:
      return {
        ...state,
        posts_loading: true,
      }
      case types.LOAD_POST_SUCCESS:
        return {
          ...state,
          posts_loading: false,
          posts: action.payload,
        }
        case types.LOAD_POST_FAILURE:
        return {
          ...state,
          posts_loading: false,
          posts_error: action.payload,
        }
        //...other actions
        default:
           return state 
        }
    }
}

Who Will Dispatch the Dispatches? Creating Our Thunk

In the ducks pattern, operations are higher-order action creators. Thunks are one category of operation. Another way to think of an operation is an action creator+. It will dispatch actions, sometimes more than one, and sometimes take care of other business logic. Again what makes thunks specific is that return a function instead of an action. 

In our operations, we’ll be deploying some combination of the three actions we defined earlier. We’ll be using Axios to make our HTTP request.

const fetchPosts = () => {
  const url = '/our-app/posts.json'
  return (dispatch) => {
    dispatch(actions.loadPostsRequest())
    axios.get(url)
      .then((response) => {
        dispatch(actions.loadPostsSuccess(response.data))
      })
      .catch((error) => {
        dispatch(actions.loadTaskHistoryFailure(error))
      })
  }
}

And there you have it! Now that you’ve written your thunk, you want to make sure it’s well tested and resilient to change. In the next article, you’ll learn exactly how to test redux thunks.

Which version of JavaScript is “Vanilla JavaScript”?

There are so many different versions of JavaScript floating around, and browser support is always changing. How do you know which features you can use without transpiling or some kind of build step?

Correct Answer: ES6 (a.k.a. ECMAS 2015) is supported in all major browsers.

In April of 2017, all major browsers added support for ES6. Opera added support the following August.

But what about Internet Explorer?

Even Microsoft doesn’t want people using IE. They are pushing hard for people to adopt Edge, which also supports ES6. Only 3% of internet traffic comes from Internet Explorer, and that number is only going to decline. Unless you are in circumstances that warrant it, you can safely ignore Internet Explorer.

So start taking advantage of those new features!

Here are some of the new features you can safely use anywhere, including in the console:

  • const variables
  • template strings
  • destructuring assignment
  • default parameters
  • arrow functions
  • promises
  • block scopes

So have fun writing better JavaScript!

Pure Array Modifications: Plain JavaScript vs. Modern JavaScript

When working with Redux or other state managers, you want to keep your code pure. That means no side effects. Instead of updating an array instead you want to return a new copy of the array with the changes applied. This is tricky with JavaScript arrays since it isn’t clear which native functions change the array, and which ones return a new copy.

Pop Quiz: array.slice() and array.splice(). How many of them affect the original array?

a) Slice is pure, splice is impure.

b) Slice is impure, splice is pure.

c) Both are pure.

d) Neither are pure.

Highlight to see the result: Slice is a pure function, but splice changes the array. Confusing, right?

To keep your array edits safe, let’s look at some functions that perform pure operations on arrays. Examples are included in both ES2018 and older versions of JavaScript. These examples make heavy use of the spread operator, so if you aren’t familiar with it this may also help you get a stronger understanding of how it works.

 

1. How to add an element to the end of an  array without modifying the original:


//ES 2018
const purePush = (arr, el) => [...arr,el]

//ES5
function purePushClassic(arr, el) {
  return arr.concat(el)
}

2. How to add an element to the beginning of an array without modifying the original:


//ES 2018
const pureUnshift = (arr, el) => [el, ...arr]

//ES5
function pureUnshiftClassic(arr, el) {
  return [el].concat(arr)
}

3. How to Combine two Arrays into a Third


//ES2018
const pureCombine = (arr1, arr2) => [...arr1, ...arr2]

//ES5
function pureCombineClassic(arr1, arr2) {
  return arr1.concat(arr2)
}

4. Remove an element from the end of the array, Without modifying the original:


//ES 2018
const pureShift = (arr) => arr.slice(1)

//ES5
function pureShiftClassic(arr){ return arr.slice(1) }

5. Remove an element from the beginning of the array, Without modifying the original:


//ES2018
const purePop = (arr) => arr.slice(0,-1)

//ES5
function purePopClassic(arr) { return arr.slice(0,-1) }

6. Insert an element at a specific index without mutating the array:


//ES2018
const pureInsert = (arr, el, i) => [...arr.slice(0,i), el, ...arr.slice(i++)]

//ES5
function pureInsertClassic(arr, el, i) {
return arr.slice(0,i)
  .concat(el)
  .concat(arr.slice(i++))
}

7. Replace an element at a specific index without mutating the array:


//ES2018
const pureReplace = (arr, el, i) =&gt; {
  let copy = [...arr]
  copy[i] = el
  return copy
}

//ES5
function pureReplaceClassic(arr, el, i) {
  var copy = arr.slice()
  copy[i] = el
  return copy
}

8. Delete an element at a specific index without mutating the array:


//ES2018
const pureDelete = (arr, i) => [...arr.slice(0,i),...arr.slice(i+1)]

//ES5
function pureDeleteClassic(arr, i) {
  return arr.slice(0,i).concat(arr.slice(i+1))
}

Bonus tip:  turn any impure array method into a pure one

All you have to is make a copy of the array first. You’ve seen it in the above examples. In ES2018, you can use the spread operator. In old JavaScript, you can use splice. For example, here’s a way to convert the reverse method into a pure operation:


//ES2018

[...arr].reverse()

//ES5

arr.slice().reverse()

Now you try! Here’s a code sandbox to try these functions

See the Pen Pure Array Modification Functions by Glenn Stovall (@GSto) on CodePen.

Want to know more? Here’s some further reading

 

 

 

 

How to Update Content Based on URL params; No Libraries Required

If you’re a frequent user of Netflix or Amazon, then you’re familiar with how they use what they know about you to tailor their platform to your tastes. Personalization is an effective marketing technique. It makes you a more engaged customer, and more likely to get out your wallet.

But you don’t have a team of data scientists or expensive enterprise level marketing tech. How can you apply personalization to your business?

Good news! None of that is required. You don’t even need any JavaScript libraries or frameworks! Here’s an example you can get started with: Changing the page based on query parameters.

The Project: Changing Headlines and Hiding Forms

We’re going to create a simple landing page, then make some optimizations:

  1. If we know the person is a subscriber, we won’t show them the opt-in email form.
  2. We’ll change the headline to make it more specific.

Perfect project for a marketing developer. The more specific your copy is, the more it will resonate with the user. Imagine if the title of this article was “Hey Matt, here’s how to optimize your landing page for your premium icon set!” For all you Matts out there, wasn’t that nice?

The Result

Here’s the final product. Below I’ll explain exactly how it works.

See the Pen Dynamic Content From Query Parameters by Glenn Stovall (@GSto) on CodePen.

Watch it in Action:

Now Learn How It Works:

First, Parse The Query String:

Fetch the query string (everything after the “?” in the URL.)  It’s referenced here:

windows.location.search

Then, parse that string into an object so that you can access specific variables. Here’s a function that handles that:


/* Converts a query string into an object. 
 * example input:  ?src=agency
 * results: { src: "agency" }
 */
function parseQuery(str) {
  //Remove '?' from beginning.
  str = str.substring(1) 
  //split the string into key value pairs
  var pairs = str.split("&amp;amp;amp;")
  //convert them into an object
  return pairs.reduce(function(map, pair) {
      console.log(pair)
      var kv = pair.split("=")
      var key = kv[0]
      var value = kv[1]
      map[key] = value
      return map
  },{})
}

It’s worth noting that every value is a String. If you want to interpret a value as an integer or float, you’ll need to use ParseInt and ParseFloat. For booleans you can use value == ‘true’

Then, Show and Hide Elements

Now that we have a usable object, we can start manipulating the page. In these examples, we’ll be using the native document.querySelector and document.querySelectorAll methods. Using native methods keeps your code portable. You can use this code anywhere from a single page application to Google Tag Manager.

Here’s the function that hides our email opt-in. If we already have the visitors email address, we don’t need to keep pestering them.


if(profile.subscriber) {
  document.querySelector(".course-opt-in").style.display = "none"
}

Finally, Update Text on The Page

Similarly, we can update text. Here’s an example that looks for every instance of a specific class, and changes the text within that element. First, the helper function that makes the updates:


function updatePlurals(text) {
  var targets = document.querySelectorAll(".target-plural");
  for(var i = 0; i < targets.length; i++) {
    targets[i].innerText = text;
  }
}

And then a switch statement to call said function.


switch(profile.src) {
  case "agency":
    updatePlurals("agencies")
    break
  case "freelancer":
    updatePlurals("freelancers")
    break
  case "startup":
  default:
    updatePlurals("startups")
    break
}

Exercise: How Can You Apply This To Your Site?

What are some ways you could make your pages resonate with your visitors more? The more resonant your content, the more helpful and persuasive you’ll be to your audience. Here are some ideas for places to start:

  • Headlines. Where could you update headlines to make them more specific?
  • Opt-ins. Where could you remove opt-ins to make the experience more pleasant for your users? Could you show different opt-ins based on what you know about them? (for example, instead of asking someone to opt-in to a newsletter, you could ask them to sign up for a free trial).
  • Calls to Action. Besides headlines, calls to actions are the most important text on your page. How could you make them more persuasive?

How to Make an AJAX Request Without Using Frameworks or Libraries

There are a lot of JavaScript frameworks out there these days. It makes it harder to choose a front-end development workflow when starting a new project and write code that’s portable between different projects. Also, using a complex framework to solve a simple problem adds unneeded complexity and risk to a project, which makes getting that project out the door slower and more troublesome.

Continue reading

Yeoman + AngularJS + Foundation: A Modern Front End Setup

With the combination of modern browsers and mobile devices having support for HTML5, CSS3, and new JavaScript APIs, front end development has become a lot more complicated, but also exciting. There has been an explosion of tools as of late, and it can be daunting to know where to get started. Here are the tools and process I use to build a new front end application from scratch.

Continue reading

AngularJS: an Overview

AngularJS is a JavaScript framework made by Google for building complex client-side applications. Angular’s killer feature is ‘directives’ that allow you to extend HTML by creating tags and attributes. Angular projects have a somewhat different structure than other JavaScript MVC frameworks, but it can be highly modular and easy to maintain once you understand the structure. Let’s take a look at the main components of AngularJS and how they work, and why you should strongly consider Angular for your next project.

Continue reading