yaya
yaya

Reputation: 8243

how react-redux gets the store object of provider?

Here is a basic react-redux app (sandbox):

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { useDispatch, Provider, useSelector, useStore } from "react-redux";
const App = () => {
  const store = useStore(); // <- how it gets the store object of Provider ?
  const state = useSelector(s => s);
  return <div>{state}</div>;
};
ReactDOM.render(
  <Provider store={createStore((state, action) => 5)}>
    <App />
  </Provider>,
  document.getElementById("root")
);

Now my question is:

How hooks like useStore gets the store object we set in <Provider store={store}> ?

If it was dom, we could use this.closest('.provider').getAttribute('store') to get the store attribute of the provider element in parents. But how we can do it in react?

I'm asking it because i want to understand how react-redux works behind the scenes.

Thanks.

Upvotes: 3

Views: 1014

Answers (1)

Christopher Francisco
Christopher Francisco

Reputation: 16278

react-redux uses a provider that holds all of the properties it works with. It allows you to pull the internals from the provider through nice APIs such as the hooks API (useStore, useDispatch), or through the connect() HOC API.

To help you visualise it in a simpler way, let's write a "mini" react-redux using React Context API

import React, { createContext, useContext } from 'react';

const InternalProvider = createContext();

/**
 * This is the `Provider` you import from `react-redux`.
 * It holds all of the things child components will need
 */
const Provider = ({ store, children }) => {
  /**
   * This `context` object is what's going to be passed down 
   * through React Context API. You can use `<Consumer>` or 
   * `useContext` to get this object from any react-redux-internal
   * child component.  We'll consume it on our `useStore` and
   * `useDispatch` hooks
   */
  const context = {
    getStore: () => store,
    getDispatch: (action) => store.dispatch,
  };

  return (
    <InternalProvider value={context}>
      {children}
    </InternalProvider>
  );
}


/**
 * These are the hooks you import from `react-redux`.
 * It's dead simple, you use `useContext` to pull the `context`
 * object, and voila! you have a reference.
 */
const useStore = () => {
  const context = useContext(InternalProvider)
  const store = context.getStore();
  return context;
};

const useDispatch = () => {
  const { getDispatch } useContext(InternalProvider);

  return getDispatch();
};


/***************************************
 * Your redux-aware components
 *
 * This is how you consume `react-redux` in your app
 */
const MyComponent = () => {
  const store = useStore();
  const dispatch = useDispatch();

  return <>Foo</>
}

const App = () => (
  <Provider store={store}>
    <MyComponent />
  </Provider>
)

Upvotes: 4

Related Questions