Categories
Redux

Accessing the Store with React-Redux

Spread the love

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to access the Redux store with React-Redux.

Accessing the Store

With React-Redux, we can access the store by defining a mapStateToProps function.

However, we can also access it in a customized way. Internally, React-Redux uses React’s Context API to make the Redux store accessible to deeply nested connected components.

Currently, React-Redux is normally handled by a single default context object instance generated by React.createContext() called ReactReduxContext .

Provider uses ReactReduxContext.Provider to put the Redux Store and the current state into context and connect uses ReactReduxContext.Consumer to read values and handle updates.

Providing Custom Context

We can provide a custom context to React-Redux via the context prop.

For example, we can pass in our own context in the following code:

import React from "re
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore } from "redux";
function count(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}
const store = createStore(count);

function App({ increment, decrement, count }) {
  return (
    <div className="App">
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <p>{count}</p>
    </div>
  );
}
const mapStateToProps = state => {
  return { count: state };
};
const increment = () => ({ type: "INCREMENT" });
const decrement = () => ({ type: "DECREMENT" });
const customContext = React.createContext();

App = connect(
  mapStateToProps,
  { increment, decrement },
  null,
  { context: customContext }
)(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store} context={customContext}>
    <App />
  </Provider>,
  rootElement
);

In the code above, we have the usual React-Redux code for connecting the store to the App component via connect .

However, we create a customContext via:

const customContext = React.createContext();

Then in the connect call, we have:

App = connect(
  mapStateToProps,
  { increment, decrement },
  null,
  { context: customContext }
)(App);

The 4th argument is { context: customContext } , which is where we set our custom context.

Also, we have:

<Provider store={store} context={customContext}>
  <App />
</Provider>

to set our context prop via context={customContext} .

Multiple Stores

We can also use multiple stores with React-Redux by nesting providers as follows:

import React from "react";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { createStore, compose } from "redux";
function countA(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
}

function countB(state = 0, action) {
  switch (action.type) {
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const storeA = createStore(countA);
const storeB = createStore(countB);
function App({ increment, decrement, countA, countB }) {
  return (
    <div className="App">
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <p>{countA}</p>
      <p>{countB}</p>
    </div>
  );
}
const mapStateToPropsA = state => {
  return { countA: state };
};

const mapStateToPropsB = state => {
  return { countB: state };
};

const increment = () => ({ type: "INCREMENT" });
const decrement = () => ({ type: "DECREMENT" });
const contextA = React.createContext();
const contextB = React.createContext();

App = compose(
  connect(
    mapStateToPropsA,
    { increment },
    null,
    { context: contextA }
  ),
  connect(
    mapStateToPropsB,
    { decrement },
    null,
    { context: contextB }
  )
)(App);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={storeA} context={contextA}>
    <Provider store={storeB} context={contextB}>
      <App />
    </Provider>
  </Provider>,
  rootElement
);

In the code above, we defined 2 separate stores by writing:

const storeA = createStore(countA);
const storeB = createStore(countB);

where countA and countB are the reducers.

Then we nest our connect calls within the arguments of the compose function to combine the connects as follows:

App = compose(
  connect(
    mapStateToPropsA,
    { increment },
    null,
    { context: contextA }
  ),
  connect(
    mapStateToPropsB,
    { decrement },
    null,
    { context: contextB }
  )
)(App);

We defined mapStateToPropsA and mapStateToPropsB to map states from the 2 stores before this call.

Then in the last argument of each connect , we pass in an object with the context that we want to use to connect the store to App .

Then in the ReactDOM.render call, we pass in:

<Provider store={storeA} context={contextA}>
  <Provider store={storeB} context={contextB}>
    <App />
  </Provider>
</Provider>

to set the store and context we want to use for each provider. The context prop of each Provider have to match with connect .

Conclusion

We can access multiple stores by nesting multiple Providers and providing a store and context for each.

The context is defined by calling React.createContext() , which is part of the React Context API used to share data between components.

Then we can use the compose function to add combine multiple connect calls together. We pass into the 4th argument of connect in each call.

We can also use the same method to customize access to a single store, except that we don’t need to call compose .

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *