DEV Community

Sadick
Sadick

Posted on • Edited on

The not so secret life of Provider in Redux

I have always asked myself what the <Provider> does and why it is a neccessity while using redux.
How does react-redux make it possible for me to access my store objects.

My inquisitive nature led me to the react redux codebase. I expected to find a large compilcated <Provider> component, but to my suprise that wasn't the case.

I have ommited some code for readability sake.

import React from "react";
import PropTypes from "prop-types";

class Provider extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.store = props.store;
  }
  getChildContext() {
    return { store: this.store };
  }
  render() {
    return this.props.children;
  }
}
Provider.childContextTypes = {
  store: PropTypes.object
};

export default Provider;
Enter fullscreen mode Exit fullscreen mode

What is the Provider doing

Provider makes use react's context api. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

The provider makes store accessible to its child components via the getChildContext method. Therefore its children can access the store with props.context.store.

const Child = ({props}) => {
  console.log(props.context.store)
  return <div>child</div>
}
Enter fullscreen mode Exit fullscreen mode

Now Child can have access to the store without us passing it down explicitly

<Provider store={store}>
  <Child/>
</Provider>
Enter fullscreen mode Exit fullscreen mode

Also note the childContextTypes that is defined on the provider class. This is needed so that react can know the shape of data we are sharing via the context.

This is how the react-redux connect function is able to get our store objects. Below is a simplified version of the connect.


function connect(mapStateToProps, mapDispatchToProps) {
  return function(Component) {
    class App extends React.Component {
      constructor(props, context) {
        super(props, context);
        this.state = context.store.getState();
      }
      render() {
        return <Component {...this.state}/>
      }
    }
    App.contextTypes = {
      state: PropTypes.object
    };
    return App;
  };
}
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
markerikson profile image
Mark Erikson • Edited

Kudos on digging into the source code! I think more people should do that - it's a great way to learn about what libraries and tools are doing.

Looking at your post, I do think the connect example is over-simplified, and the ...this.store part especially is misleading. Dan Abramov wrote a miniature version of connect here. Here's the equivalent part from that example:

    return class extends React.Component {
      render() {
        return (
          // that renders your component
          <WrappedComponent
            {/* with its props  */}
            {...this.props}
            {/* and additional props calculated from Redux store */}
            {...mapStateToProps(store.getState(), this.props)}
            {...mapDispatchToProps(store.dispatch, this.props)}
          />
        )
}

Also, it's very possible that in an upcoming version of React-Redux, the Provider component will be very different. I'm currently researching how to use the new React context API inside of React-Redux, and have an open pull request with an early proof of concept. That PR actually switches from having individual connected components subscribe to the store, to having Provider subscribe instead. I'm hoping to do more experimentation with this in the near future.

Collapse
 
sadick profile image
Sadick

Thanks for pointing that out. The thing i see missing is the call to getState. I was only trying to show how the store is accessed.

Collapse
 
markerikson profile image
Mark Erikson • Edited

Yeah, that was my point - there's a big difference between passing ...store as props, and passing ...mapState(store.getState()) as props :)

Although, now that I re-read that last example carefully, you've got: this.store = context.store.getState(), which is kinda mis-named in a different way than I thought.

Anyway, if you enjoyed that look inside, you might be interested in reading some of these other articles explaining how Redux and React-Redux work .

Thread Thread
 
sadick profile image
Sadick

Thanks I now see your point.