loading...
Cover image for A Simple Guide to React Context with Hooks

A Simple Guide to React Context with Hooks

keke_arif profile image Keke Arif ・3 min read

It took me a while to get my head around using React Context with hooks, all the tutorials I read failed to explain it in a simple manner or seemed focused on class syntax. The class syntax is due to die soon so let me give it a try.

Why use Context?

Passing props down multiple child components can become unwieldy.

const [someState, setSomeState] = useState('cool value');

return <SomeBigDaddyComponent someState={someState} />

Now the implementation of SomeBigDaddyComponent.

const SomeBigDaddyComponent = ({ someState }) = {
  return <SomeMediumDaddyComponent someSate={someState} />
}

Now the implementation of SomeMediumDaddyComponent.

const SomeMediumDaddyComponent = ({ someState }) = {
  return <SomeSmallDaddyComponent someSate={someState} />
}

Now the implementation of SomeSmallDaddyComponent.........
It's becoming a mess right? This is about the right time to use context.

Creating and Broadcasting a Context

Context is essentially a way to broadcast data down a chain of child components without passing props. It's easier to explain by just doing it. Let's create a very simple context.

import React from 'react';

const CoolMessageContext = React.createContext('hello hello hello');

export default CoolMessageContext;

I initialized the context above with a simple string, however this can be any value and usually an object would be used. Now lets see how the context works. Consider App.js.

import React from 'react';
import CoolMessageContext from './CoolMessageContext';

const App = () => {
  return (
    <CoolMessageContext.Provider value={'bye bye bye'} />
      <SomeBigDaddyComponent />
    </CoolMessageContext.Provider>
  );
}

The components that will have access to the context's value are wrapped in Provider. This is essentially saying "Hey I'm the provider of the value, anything below me will get that value". In the example above SomeBigDaddyComponent can get the value and also its children, SomeMediumDaddyComponent and SomeSmallDaddy. Anything above the provider can not access the value.

const App = () => {
  return (
    <div>
      <SomeOtherComponent />
      <CoolMessageContext.Provider value={'bye bye bye'} />
        <SomeBigDaddyComponent />
      </CoolMessageContext.Provider>
    </div>
  );
}

SomeOtherComponent does not have access to the value because it is sitting above the provider. Note that an initial value must be provided, here I provide 'bye bye bye'. Although an initial value was set with createContext this is really just a fail-safe value in case a value isn't provided when setting the provider.

Getting the Context's Value

Now the value is being broadcast we can go ahead and access it from any of the children. To get the value we will use the hook useContext.

import React, { useContext } from 'react';
import CoolMessageContext from './CoolMessageContext';

const SomeSmallDaddyComponent = () => {
  const coolMessage = useContext(CoolMessageContext);
  return <h1>{coolMessage}</h1>
};

export default SomeSmallDaddyComponent;

The useContext hook is initialized with the context object and so that the value can be accessed without messy prop passing. You can think of useContext as providing a teleport for the value so that it can teleport down into the component that needs it.

Setting a Context's Value

A context's value can also be changed from anywhere in a similar manner if state is used.

import React from 'react';

const ObjectContext = React.createContext({
  object: {
    number: 0,
    word: 'hello'
  },
  setObject: () => {}
});

export default ObjectContext;

The above context is similar to what we used before but also has a property to store the set function for setState.

import React, { useState } from 'react';
import ObjectContext from './ObjectContext';

const App = () => {
  const [object, setObject] = useState({
    number: 1,
    word: 'bye'
  });

  return (
    // ES6 Object Property Value Shorthand 
    <ObjectContext value={{ object, setObject }} />
      <SomeBigDaddyComponent />
    </ObjectContext >
  );
};

The value above is set with the state object and also the state set function. Now setting the state from anywhere is the same as accessing the value.

import React, { useContext } from 'react';
import ObjectContext from './ObjectContext';

const SomeSmallDaddyComponent = () => {
  const { object, setObject } = useContext(ObjectContext);
  const clickHandler = () => {
    const objectCopy = {...object};
    objectCopy.title = 'wow new title!';
    setObject(objectCopy);
  }
  return <button onClick={clickHandler}>{object.title}</button>
};

export default SomeSmallDaddyComponent;

That's the basic rundown of contexts! Let me know if I missed anything or you have any questions. If you like the post give me a follow on Twitter @keke_arif . Cheers.

keke

Posted on by:

keke_arif profile

Keke Arif

@keke_arif

🇬🇧 British iOS developer based in Taipei, Taiwan 🇹🇼 Controlled by cats 🐈 Swift and React JS are my poisons.

Discussion

markdown guide
 

Hi, thanks for this. Looks like there is a typo in one of your spreads where it goes something like: {..object} when it should be {...object}

 

Whoopsie! Fixed. Thanks!