DEV Community

independnt
independnt

Posted on

React Context

Since graduating from The FlatIron School, Redux has been the jelly to Reacts peanut butter. The pasta and meatballs. Stone Cold Steve Austin and Beer (Although I hear he's recently quit drinking. Besides the point). I could go on. However, I've recently stumbled upon React Context which is a fairly newer paradigm in terms of handling state in components. Maybe I don't always need Redux, because with Context, I can pass down state to components without having to use props. My thoughts when I heard this? Whaaaaaaaaaaaat. According to the documentation, it should be used sparingly because it can make component reuse difficult. Let's use Context to refactor a crypto dashboard I'd been working on from a previous blog post.

The first thing that needs to happen, is we need to create a Context and in the scope of my current project, I simply created a new file named "AppProvider.js". This is not a component that will render anything other than it's children. It will more so be a container for the projects state. First thing's first, we'll import React and create a new Context using the React createContext function:

    import React from 'react';
    export const AppContext = React.createContext()

Now we have a Context object. The key aspect of understanding how Context works is understanding the Provider and the Consumer relationship. Keep in mind, I'm still learning and this is all to the best of my understanding. Providers are React components that accept a value prop, in this case, state. Once the Providers value changes, all Consumers of that Provider will re-render. A Consumer is also a React component which according to the docs, subscribes to context changes.

With that said, let's move forward. I'm refactoring how state is handled in my current project, in this case, how the application knows which page to render. So in my newly created AppProvider.js I will create the state, as I would in any component like so:

  export class AppProvider extends React.Component {
      constructor(props){
        super(props);
        this.state = {
          page: 'dashboard',
          setPage: this.setPage
    }
  }
}

Now you'll notice that I also have something called setPage in the state. That will be my updater function. I know it's strange to pass functions into the state, but according to the Context docs, it indicates that state should hold the updater function. So let's define that function now:

    setPage = page => this.setState({page})

Last, let's create our Provider, as mentioned earlier.

    render(){
    return (
      <AppContext.Provider value={this.state}>
        {this.props.children}
      </AppContext.Provider>
    )
  }

Now, all children can have access to the state, all that's left is to choose our consumers, and import them where necessary. First, i need to wrap the component that needs access to the state in my new AppProvider object. I'll go into the needed file and import/wrap:

import {AppProvider} from './AppProvider'

class App extends Component {
  render() {
    return (
      <AppLayout>
        <AppProvider>
          <AppBar/>
          <WelcomeMessage/>
        </AppProvider>
      </AppLayout>
    );
  }
}

Now AppBar and WelcomeMessage have access to the information needed. Going into AppBar, we can now create Consumers by creating a ControlButton function and returning a Consumer component:

function ControlButton({name}){
  return (
    <AppContext.Consumer>
      {({page, setPage}) => (
        <div
          onClick={() => setPage(name)}
        >
          {name}
        </div>
      )}
    </AppContext.Consumer>
  )
}

My function takes a name (which is labeled in a name prop in each individual ControlButton) and returns AppContent.Consumer, creating a new Consumer component, which then takes the current page in the Provider state, and the setPage function and returns a div that has an onClick handler, which now uses the setPage function to change the page in our Provider state.

Phew. Well, that's just the basics for now, more experimenting with Context later. Signing off.

Top comments (0)