Reputation: 8243
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
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