Understanding React useContext

by Bob MacNeal, 29 August 2019

In React’s brief history, one challenge has been how to share application state ― the ever-changing application data ― as needed within the component hierarchy of a typical React application. Sharing state falls under the auspices of state management.

State Management

State management is a challenge for single page application libraries like React (see Brief History of React State Management).

React v16.8, released in February 2019, simplifies state management with the introduction of hooks. The useState hook, for component-level state management, and the useContext hook, for cross-component sharing and feature-level or application-level state management, are valuable additions to the React toolbox.

“Hooks let you use state and other React features without writing a class.”

React v16.8: The One With Hooks

Hooks have caused the imminent obsolescence of class components in favor of plain JavaScript functions. Using hooks in functional components, we no longer rely on hacks like lifecycle methods to manage state.

react-wizard Demo

A step-by-step input wizard, implemented in the open source react-wizard application is used to demonstrate how and why to take advantage of the useContext hook.

A wizard workflow is applied in react-wizard to a hypothetical task definition & scheduling feature (Figure 1).

Figure 1 – Step #3 of the wizard workflow

An actual task definition and scheduling feature would require many more configuration steps and additional input types, but the pattern devised in react-wizard is conceived to be extensible.

Walk-through

All code in the walk-through can be viewed in detail in the react-wizard repository. Readers may also clone the repository, then follow the setup steps in the README.md to run the application locally.

The wizard feature is contained in Wizard.js. Wizard.js has a top level WizardProvider component.

WizardProvider represents the context wherein application state, named WizardContext, is stored. WizardProvider has three child components from top to bottom: StepIndicator, StepForm, and StepNavigator (Figure 2)

Figure 2Wizard.js

At the top of the view, the StepIndicator component is a visual indicator that communicates the current step to the user (Figure 3).

Figure 3StepIndicator.js

Below the StepIndicator is the StepForm component. The StepForm component has all of the form elements needed for user input (Figure 4).

Figure 4 – StepForm.js

The StepForm component is capable of rendering a dynamic number of form elements based on the content of the steps described by the initial state set in the WizardContext (more on WizardContext later).

Finally, beneath the StepForm component, is the StepNavigator component (Figure 5). The StepNavigator component has two buttons to navigate to the next or previous step.

Figure 5StepNavigator.js Previous button disabled in Step #1

The WizardProvider and its WizardContext enable the sharing of a state object within the StepIndicator, StepForm, and StepNavigator components.

When a user clicks the Next button on Step #1, a click handler in StepNavigator changes the active step in the state object. The StepIndicator component then responds to the active step state change by rendering itself as Step #2 (Figure 6).

Figure 6 – Re-renderer as Step #2

State Updates via useContext

At each workflow step, StepForm.js (Figure 7) handles storing the user’s input via the handleChange function (line 42). The handleChange function accesses the state object via the useContext (WizardContext) hook (line 20).

Figure 7 – Handling changes in form input

WizardContext

WizardProvider, and its application state representation WizardContext (line 3, Figure 8), provide a state object for subsequent state updates as the user progresses through the steps. The state object is given an initial state with input values set to empty string. The initial state provides the name/value armature for each step.

The initial state includes definitions for each step represented by a 4-step steps array (line 8). This array is extensible to N-steps following a similar pattern.

Each element of the steps array indicates which form elements are needed at each step so that when the activeStep (line 7) changes, each step knows what input elements to render (text input, a checkbox, or a select) in StepForm.

Note that the first step in the steps array below calls for an element of type text (line 17).

Figure 8 – WizardContext representation of application state

Save Form Input

When the user progresses to the last step, the Next button is disabled and a Save button appears (Figure 9).


Figure 9 – Saving input in the last step

Clicking Save outputs a JSON object to the console of the form shown in Figure 10.

Figure 10 – Payload to POST to a data store

It’s left to readers to add form validation, wire up a POST to a backend data store, and to extend the steps array to N-steps with all required task configuration input.

Remarks

Prior to React hooks, state was shared either by prop drilling or by wiring up a state container like react-redux. Both approaches have one or more of the drawbacks of tediousness, complexity, or excessive boilerplate.

The useState hook (for component-level state management) and the useContext hook (for feature/application state management) have significantly simplified state management in the typical React application.

Brief History of React State Management

by Bob MacNeal, 28 August 2019

Over React’s brief history, one challenge has been application state management.

Unlike first-generation web applications that served web pages via requests and responses off of specific state-describing routes, React single page applications (SPAs) typically don’t use much deep linking. More often, an entire React SPA exists within ― and is described by ― a few explicit routes.

Managing component-level state and application-level state has been a burr under the React developer’s saddle.

Component-level state are potentially changing properties that are only needed within a component (e.g., a boolean property indicating to show or hide a message depending on the user’s input).

Application-level state are the potentially changing properties that other components might care about. For example, given a widgets list component and a create widget component, the widgets list component should care when a widget has been created so it can render an updated list.

Iteration One: Props Drilling

In React days of yore, prop drilling was used to maintain and share the state of potentially updatable properties. With prop drilling, we passed (or drilled down) properties and functions to each child in the component tree.

Prop drilling works well, but it’s tedious, often untidy, and can be risky without explicit type checking.

Iteration Two: State Containers

Enter popular state containers like react-redux and MobX. Now developers need not rely solely on prop drilling because predictable, scalable, state management had arrived as an appendage to React, albeit with odd-looking connect syntax required to wire up state sharing with react-redux.

State containers are industrial-strength state management. However, they can be cumbersome, are sometimes inscrutable during troubleshooting, and typically require boilerplate code.

Bad habits ensued with state containers. Chief among the anti-patterns I observed is that that developers tended to stuff all of their state into redux, even local state which other components did not care about.

Iteration Three: Hooks

React hooks arrived early February 2019 with the release of v16.8.

The useState hook for component-level state management, and the useContext hook for cross-component state management, have significantly simplified state management in React applications.

Conclusion

React state management now has several options. I find React’s useState and useContext hooks are simpler and less cumbersome than react-redux.

Of course there’s no one-size-fits-all with state management. One’s approach should always be guided by pragmatism.

“Keep state as local as possible and use context only when prop drilling really becomes a problem. Doing things this way will make it easier for you to maintain state interactions.”
– Kent C. Dodds

Application State Management With React

For me there’s a tension between the purpose served and the resistance to implementation. I’m reminded of an Extreme Programming mantra:

“Do the simplest thing that could possibly work.”

Extreme Programming Pocket Guide, Chromatic

Resources

Application State Management With React, Kent C. Dodds;

Prop Drilling, Kent C. Dodds;

Exploring React Hooks – 1

by Bob MacNeal, 3 Mar 2019

React, the JavaScript library for building UI components, now supports Hooks.

Hooks, from the Facebook engineering team, resolve a variety of issues and goofy workarounds in the React space (e.g., life-cycle methods, connecting to an application store, and passing stateful logic between components, to name a few).

I embarked on a prototyping exercise to determine how I might best use a few of the built-in hooks, like useState, useEffect, and useRef, in functional components.

Once comfortable with a few of the built-ins, I made a custom hook called useAxiosGetItems. I plan to re-use this hook when I need to wire up GET requests in service-level functions. Indeed I use a slightly modified version of it in the sequel to this post Exploring React Hooks – 2.

The first prototype is called simple-hooksMaterial-UI React components and icons are used for design and functional simplicity.

The simple-hooks application demonstrates how I used hooks to back an interface consisting of four tabs meant to trigger the display of the following item lists:

Todos, Posts, Photos, and Users.

Screen Shot 2019-03-02 at 4.15.41 PM.png

The item lists are fetched from the JSONPlaceholder API.

JSONPlaceholder, the self-proclaimed “Fake Online REST API for Testing and Prototyping”, is a low-resistance API that proved quite helpful in my prototyping to explore React hooks.

Code

The main container in the simple-hooks prototype is the functional component Resource that includes navigational tabs and an ItemList component to display the item lists of the selected resource.

useState

Note the use of useState (below). The useState invocations store the state of which UI tab was clicked (i.e., which resource type the user selected). The const initializes the default state to display TODOs. The second const initializes the default display fields for TODOs. The function handleSwitchTab responds to tab click events by updating the resource type and resource fields.

Screen Shot 2019-03-02 at 4.35.53 PM

resource.js component

The syntax of useState is:
const [propertyName, setPropertyName] = useState(initial condition)

Custom Hook

The custom hook I created uses the useEffect and useState hooks. The motivation behind the custom hook is to provide a generalized approach to making GET requests using the axios HTTP request library.

Screen Shot 2019-03-02 at 4.44.03 PM

useAxiosGetItems is passed a URL. In this case, the URL points to various resources available in the JSONPlaceholder API.

The function makes an asynchronous request. It returns three entities at different times:

  • loading – A boolean that is true until the HTTP request resolves, then changes to false. This loading variable allows for a progress indicator to be temporarily displayed in the UI while the request in in progress.
  • listItems – When the request for the resource items resolves, an array of the requested resource (i.e., ToDos, Posts, Photos, or Users) is populated and returned with loading toggle to false.
  • error – Should an error occur, an object including an HTTP return code and a descriptive message is sent back for display in the UI.

Conclusion

React hooks negate the need for confusing life-cycle methods and enable simple state management in functional components. They also reduce some of the boilerplate required by stateful class components.

Code for this prototype is available in the simple-hooks git repository.

The second prototype I made exploring React hooks is a search application called simple-hooks-search that forms the basis of Exploring React Hooks – 2.

Jump to Exploring React Hooks – 2.

Exploring React Hooks – 2

by Bob MacNeal, 3 Mar 2019

React, the JavaScript library for building UI components, now supports Hooks. In the previous post, Exploring React Hooks – 1, I described an exercise to determine how to best use React hooks in the context of building a prototype called simple-hooks.

In this sequel, I demonstrate how I used React hooks in a second prototype with different requirements, namely a search application called simple-hooks-search.

Like simple-hooks, the search application simple-hooks-search uses Material-UI React components and icons for design and functional simplicity.

React hooks were used to back a simple search application UI (below) with the following elements:

  • input for search terms;
  • an X button to clear the search;
  • a button to submit a search; and
  • a search results list.

Screen Shot 2019-03-03 at 2.55.34 PM.png

Code

The main container in the simple-hooks-search prototype is the functional component Search. This container component includes a component for the form called SearchForm and a component for the results called SearchResults.

In Search (below), useState stores the search term. Setting the search term causes a re-render.

The syntax of useState is:
const [propertyName, setPropertyName] = useState(initial state)

Screen Shot 2019-03-03 at 3.21.51 PM.png

Search.js component

SearchForm

The SearchForm component has a handleSearch function to process search term submissions and a handleClearSearchTerm function to clear the form. Note that handleClearSearchTerm also uses a useRef hook.

Screen Shot 2019-03-03 at 3.36.42 PM.png

SearchForm.js component

The useRef hook (above) is used to set focus on the text input upon clearing the search term.

SearchResults

When a search term is submitted from the SearchForm component, results are fetched from the Hacker News search API for display in the SearchResults component. The salient features of the SearchResults component are:

  1. It receives a search term as a prop from its parent component Search;
  2. It invokes a service layer function called searchHackerNews(searchTerm) to fetch results;
  3. It displays a CircularProgress loading indicator while the request resolves; and
  4. Finally, once the server request resolves, it loops through the listItems adorning them with markup for display. Also note that any error would be displayed (e.g., should the API request fail).

Screen Shot 2019-03-03 at 3.48.36 PM.png

SearchResults.js component

The function searchHackerNews uses a custom hook called useAxiosGetItems. The custom hook takes a URL and the name of the results array in the response from the server as parameters.

Screen Shot 2019-03-03 at 3.54.40 PM.png

searchService.js

Custom Hook

The custom hook useAxiosGetItems has been slightly repurposed (from that used in Part 1) to accommodate the fact that the Hacker News search API returns an array called hits within a response object. The hits array contains the search results we want to display.

Line #14 calls below calls setListItems on response.data[itemListName] where itemListName equals “hits”.

Screen Shot 2019-03-03 at 3.59.59 PM.png

useAxiosGetItems.js

The custom hook uses the useEffect and useState hooks. It returns search results in listItems, a loading boolean for a progress indicator, and any errors that occur during the request (line #25 above).

An asynchronous request is made that returns the following entities (at different times):

  • loading – A boolean that is true until the request resolves, then changes to false. This loading variable allows for a progress indicator to be temporarily displayed in the UI while the request in in progress.
  • listItems – When the request for the resource items resolves, an array of the search results is plucked from the hits array and returned with loading toggle to false.
  • error – Should an error occur, an object including an HTTP return code and a descriptive message is sent back for display in the UI.

Conclusion

With the simple-hooks-search prototype, I once again confirmed that React hooks negate the need for life-cycle methods and enable simple state management in functional components. As with the simple-hooks prototype, hooks also reduce some of the boilerplate inherent in stateful class components.

Code for this prototype is available in the simple-hooks-search git repository.

Note that the first prototype I made simple-hooks, forming the basis of Exploring React Hooks – 1, has similarities but subtle differences to the simple-hooks-search prototype.

Jump back to Exploring React Hooks – 1.

The Big Wave Operating System

I surfed in my teens on tame East Coast waves. The draw to surf and to all aspects of water waves has never left me.

I seek and study waves in lakes, rivers, oceans, storm sewers, and boiling hot springs. And like a kid with a shoe box full of treasures, I have mentally cataloged all of the famous surf breaks from the chilly shores of Lake Superior getting pounded by an October gale to Bali the mystical Island of Temples with its thousand surfing waves.

Mavericks in a legendary Northern California wave near Half Moon Bay that breaks a half-mile out to sea and gets downright perilous to surfers when the winter swells get juicy.

Mavericks is also the name given to Apple’s new operating system upgrade.

Mavericks is not so much the inspiration for a Beach Boys song as it is a symbol of Melvillian existential struggle.
― Stewart Sinclair

As an late Apple products convert, Mavericks strikes me as an appeal to the existential extremes of the extreme sports universe and a curious marketing decision. As a wave Mavericks is one of the ultimate big wave machismo rides on the globe — a death defying free fall down a Matterhorn of water chased by an avalanche of roiling whitewater.

As for Mavericks the OSX upgrade, I haven’t downloaded it because I rely on a MacBook Pro to ply my trade. I am patiently waiting for my smarter teammates to resolve any compatibility kinks with Chrome Driver that might confound our integration tests and potentially munge other development artifacts so I don’t end up dead in the water.


REFERENCES

Not What, But Who

I’ve been moving from project to project for quite some time now. What I’ve realized is that for most professional gigs, it’s not what you’re doing that’s important as much as who you’re doing it with.

I recall a time when my teammates called me Bobby Tables for an entire 2-week iteration. Bobby Tables is developer humor.

Like many of the teams I have been fortunate to work with, everyone was productive but more importantly, our days were humor-filled.

So whenever I piss and moan about this technology stack or that technology stack Silverlight, I have to remind myself…

It’s the people, dummy

When Did Agile Jump the Shark?

I am bullish on what agile has taught us. I am bullish on the productivity gains realized by agile teams around the world.

I groove on discovery; that is, the discovery that happens by having working software at iteration one. Discovery is fun.

But I use a lowercase “a” in agile. “a” signifies pragmatism. And, there are smells.

I invite you to have some fun considering that critical flash in time when agile Jumped the Shark.

I see Fonzie rapidly approaching across the lake on water skis.

Which option in the LinkedIn poll would you select?

Do you have an option I missed?

Dessert Only, Skip Vegetables

Dessert Only, Skip Vegetables is inspired from James Shore’s post The Decline and Fall of Agile

“…teams say they’re Agile, but they’re just planning (and replanning) frequently. Short cycles and the ability to re-plan are the benefit that Agile gives you. It’s the reward, not the method. These pseudo-Agile teams are having dessert every night and skipping their vegetables. By leaving out all the other stuff–the stuff that’s really Agile–they’re setting themselves up for rotten teeth, an oversized waistline, and ultimate failure.”
–James Shore

Dogmatic Bandwagon Traction

When colleagues start splitting hairs about what is and what isn’t agile, and when colleagues counsel against something, saying you should, or you shouldn’t, watch out! It might well be that the Method-ists are gaining traction and it could be time to get out of Dodge, or at least gallop off to the city limits.

Scrum Licenses User Groups

Does having the Scrum Alliance issue licenses to users groups strike you as regressive, or just plain silly?

If I hand you a gun, does that guarantee you’ll shoot yourself in the foot, or does it only increase the probability?

See Scrum User Group License.

Brand-Aware Conferences

Branding is cool, but branding around an open-minded approach is a sticky wicket. Brand-ism refers to an ideology, a sentiment, a form of culture, or a social movement focusing on the brand.

Brandism breeds over-zealous partisanship – like Nationalism. And authoritarian Brandism begets brand Fascism.

Software Replaces Post-It Notes

Agile software tools are a hindrance. Why?

  • Critical information is frequently obscured;
  • Several popular tools have serious usability issues;
  • They’re frequently the wrong fidelity or weight; and
  • While admittedly helpful to PMs and Scrum Masters, they’re confusing to product owners and they’re counter-productive for developers.