Data-Driven Functional Components via Ajax Featuring Webhooks and Redux
Tags: react, redux, javascript
Published: 2020-03-11 12:23:21

---
title: Data-Driven Functional Components via Ajax Featuring Webhooks and Redux
published: true
description: React Hooks introduced many exciting possibilities. In this post, we use Hooks along with Redux to manage application state - no need for any ugly hacks.
tags: react, redux, javascript
canonical_url: https://blog.jscrambler.com/data-driven-functional-components-via-ajax-featuring-webhooks-and-redux/
cover_image: https://blog.jscrambler.com/content/images/2020/03/jscrambler-blog-data-driven-functional-components-ajax-webhooks-redux.jpg
---

Once upon a time, class components were the only way to hook into lifecycle methods. This, for example, allowed the component to load initial data via Ajax on mount. The lifecycle method `componentDidMount` worked well for this use case. This forced the component to manage its own state and did not come without faults.

One gotcha was being able to manage the state with Redux. When Redux wanted to reload component data, it was hard to do without ugly hacks. This is because it was doing state management in two places, both in the component itself and Redux. As class component complexity grew, so did the hacks.

Enter [Hooks](https://blog.jscrambler.com/introducing-react-hooks/?utm_source=dev.to&utm_medium=referral&utm_campaign=data-driven-functional-components), a new way to manage state without class components during initial load. The idea is to let the Redux store manage state without lifecycle methods. This allows code reuse because state management gets encapsulated in the store. When dispatch actions fire across, stored `state` has all there is to know about each component.

In this take, we’ll delve into Hooks to tackle this common use case. Loading initial component data while letting Redux manage state has its benefits. To keep focus on relevant code, we’ll skip setting up a new code project. All code samples are on [GitHub](https://github.com/JscramblerBlog/functional-components-ajax-webhooks).

## Redux State to Props

At initial load, there are three props we care about: `isInit`, `isLoading`, and `isError`. The `isInit` prop signals to the component that it is time to begin loading data. While Ajax is waiting for a response, `isLoading` can show a user-friendly loader in the UI. Then, if there are any errors, `isError` puts the component in an error state.

Therefore, the initial state in Redux can be:

```javascript
const initialState = {
  firstName: '',
  isInit: false,
  isLoading: false,
  isError: false
};
```

We appended `firstName` to the state since it is the data coming back as the response. Because Redux encourages a single store, this response data can live anywhere. For example, a parent component can manage loading state, while a child component encapsulates response data. To keep this example simple, we put this in the same hierarchy.

## Redux-Thunk

These three props act like control flags. The goal is to support every event that happens during load. To flip each flag, create these action types:

```javascript
const DUMMY_LOADING_STATE_DATA = 'DUMMY_LOADING_STATE_DATA';
const DUMMY_UPDATE_STATE_DATA = 'DUMMY_UPDATE_STATE_DATA';
const DUMMY_ERROR_STATE_DATA = 'DUMMY_ERROR_STATE_DATA';
```

Fire dispatch messages across the store by creating action functions with `payload` or `error`:

```javascript
export const showLoadingState = () => ({type: DUMMY_LOADING_STATE_DATA});
export const updateStateData = (state) => ({type: DUMMY_UPDATE_STATE_DATA, payload: state });
export const errorStateData = (reason) => ({type: DUMMY_ERROR_STATE_DATA, payload: reason, error: true })
```

Then, put in place the Redux-Thunk that begins initial load:

```javascript
const loadInitStateData = () => async (dispatch, getState, axios) => {
  dispatch(showLoadingState());

  try {
    const url = '/person.json';
    const response = await axios.get(url);

    return dispatch(updateStateData(response.data));
  } catch (reason) {
    return dispatch(errorStateData(reason.message));
  }
};
```

<a href="https://jscrambler.com/signup?utm_source=dev.to&utm_medium=referral&utm_campaign=data-driven-functional-components"><img alt="Try Jscrambler For Free" src="https://media.jscrambler.com/blog/V1-freetrial.jpg"></a>

Note the dispatch `showLoadingState`; this signals the component to wait for response data. On success, `payload` has the Ajax response. On failure, `reason` has the error message with an `error` flag. This is a useful pattern to send dispatches in Redux.

Dispatch actions that fire across the store have the following properties:

- _type_: Required. Message event taking place during load.
- payload: Optional. Object with response data on success, or error message on failure.
- error: Optional. A boolean that when true says the payload contains an error message.

Finally, all the reducer must do is manage the loading state:

```javascript
const dummyReducer = (state = initialState, action) => {
  switch (action.type) {
    case DUMMY_LOADING_STATE_DATA:
      return {...state, isLoading: true, isInit: true};

    case DUMMY_UPDATE_STATE_DATA:
      const {firstName} = action.payload;
      return {...state, firstName: firstName, isLoading: false};

    case DUMMY_ERROR_STATE_DATA:
      return {...state, isError: true, isLoading: false};

    default:
      return state;
  }
};
```

The `initialState` is set so the component can begin loading. Redux persists `isInit` state once this control flag flips to true, so it knows not to reload. This is because Redux works like a state machine. The spread `...state` maintains previous state data in the store. One gotcha is to be sure to set `isLoading` to false on error. This is to prevent the component from appearing frozen in the UI. Customers might get the wrong idea when components never load and do not land in a proper error state.

## Functional Component

With all the hard work done in the Redux store, the component can focus on a single concern:

```javascript
const DummyComponent = ({isInit, isError, isLoading, loadInitStateData, firstName}) =>
  <>
    {useEffect(() => {!isInit && loadInitStateData()})}
    {isLoading && (<p>Loading...</p>)}
    {isError && (<p>An error occurred.</p>)}
    {!isLoading && !isError && isInit && (<p>Hello {firstName}.</p>)}
  </>;
```

Each control flag flips certain pieces of the UI. The props drive behavior depending on how each is set in the object parameter. This makes the component testable because it follows a functional paradigm. Each permutation of inputs has a _one-to-one_ relationship to the rendered output. Note the use of `useEffect`. This is a Hook that executes at re-render but notice the dispatch is behind a control flag. This gives control back over to Redux so it can do its job, which is to manage the state.

Be sure not to wrap Hooks around any conditional logic. React catches this during render and fails to mount the component. A better idea is to put any control flags inside the callback. This is because functional components must execute Hooks at re-render.

## Conclusion

Hooks are an exciting new way to work with functional components.

This is one way React components embrace the functional paradigm. With a Redux store, Hooks level up because it benefits from this state machine. By letting Redux manage state, it keeps separation of concerns and clean code.

As a closing note, pay special attention to JavaScript source code protection if you're developing commercial or enterprise apps. You can do this by starting a free <a href="https://jscrambler.com/signup?utm_source=dev.to&utm_medium=referral&utm_campaign=data-driven-functional-components" target="_blank">Jscrambler trial</a> - and don't miss <a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=data-driven-functional-components" target="_blank">our guide</a> for protecting React apps.