0

My app is like this:

Gatsby project

index.tsx - Entry point of app - I call

<Provider store={store}>
   <HomePage />
</Provider>

HomePage.js uses mapStateToProps and uses connect(mapStateToProps)(HomePage)

Inside my HomePage, of course I use multiple React components. And I can make use of the store, read/write of anything that happens on that HomePage.

On my Homepage, I have links to ActivityPage. Once I click on this page and land there - problem starts.

ActivityPage makes use of multiple sub-components to achieve tasks. How do I access read/write from ActivityPage?

I am unable to useDispatch to write or even read from the store. I can see the store on my ReactDev tools, but on trying to read/write I get 11 errors, mostly along the lines of I need to wrap Components with <Provider>

I read different solutions on Stack Overflow which suggested that I need to have mapStateToProps and use connect on whichever Component I need access the store.

This is not working, as I am specifically looking to get access to the store from a 'new page'. Do I need to go and make another store for my child pages? Help please. error stack trace:

Linda Paiste
  • 28,886
  • 4
  • 42
  • 71
  • Is `ActivityPage` a React component? Is it a child or grand-child of the `HomePage` component? – Eldshe Feb 28 '21 at 22:09
  • ActivityPage - React component - Child Structure of my project: ``` ===> ==> Parent => Child => G.Child``` – user3547204 Feb 28 '21 at 22:11
  • and what kind of `link` gets you to `ActivitiyPage` – Eldshe Feb 28 '21 at 22:15
  • I am using `import { Link } from 'gatsby';` then on a button Click on I am loading my ActivityPage like this ``` Visit ActivityPage ``` ActivityPage is a functional React Component – user3547204 Feb 28 '21 at 22:22
  • I found something along the lines of - I have to wrap it with a root element, but I don't understand how to apply this in this scenario https://github.com/gatsbyjs/gatsby/tree/master/examples/using-redux – user3547204 Feb 28 '21 at 22:33
  • You could have a different `Provider` with the same `store`. That would be really unusual but I think it should work. It needs to be the same store instance or else each page will have a separate redux state. For a typical React app, you would put the `Provider` in your highest level `App` component around everything, but I guess Gatsby pages are all independent. – Linda Paiste Feb 28 '21 at 23:27
  • There is some discussion that you want the same store instance across every page for the browser rendering, but separate instances with an initial state for the SSR version: https://github.com/gatsbyjs/gatsby/pull/11134 – Linda Paiste Feb 28 '21 at 23:31

2 Answers2

7

Your component must be inside of a redux Provider component in order to use the redux hooks useSelector and useDispatch or the connect HOC.

In a typical React app you would place the Provider in your App component which is a parent of everything. However Gatsby uses a different setup where each page is totally independent, so there is no shared parent where we can place the Provider.

What Gatsby does have is an API for overriding customizing behaviors by defining functions in configuration files. There are a bunch of files that you can place in the root of your app, in the same folder as package.json and outside of src. The two that we will use here are gatsby-browser.js, which controls the client-side, and gatsby-ssr.js, which controls the creation of static HTML pages through server-side rendering. Both of these files support a function called wrapRootElement.

We use the wrapRootElement function to place our Redux provider as a wrapper around every page. Since we are using the same function in two files, the official "using-redux" example defines that function in a separate file and imports it into both of the configurations. wrap-with-provider.js is not a special file name, it's just a holder for the function.

A wrapRootElement function receives the element as a prop which is similar to the children prop. Our function creates a store instance and returns a Provider with that store which has the element as its child. We are creating the store in this function, so if your current redux file is exporting a created store as a constant, you'll want to export a callable function that creates the store instead. You can see their example here.

wrap-with-provider.js

import React from "react"
import { Provider } from "react-redux"

import createStore from "./src/state/createStore"

// eslint-disable-next-line react/display-name,react/prop-types
export default ({ element }) => {
  // Instantiating store in `wrapRootElement` handler ensures:
  //  - there is fresh store for each SSR page
  //  - it will be called only once in browser, when React mounts
  const store = createStore()
  return <Provider store={store}>{element}</Provider>
}

Again, this file does not manipulate Gatsby behavior on its own. We need to export its value and assign it to a special variable in a configuration file to do that. Here are those files:

gatsby-browser.js

import wrapWithProvider from "./wrap-with-provider"
export const wrapRootElement = wrapWithProvider

gatsby-ssr.js

import wrapWithProvider from "./wrap-with-provider"
export const wrapRootElement = wrapWithProvider

The content is the same in both. All we are doing is importing the function that we created in wrap-with-provider.js and assigning it to the special named variable wrapRootElement which controls behavior.

Linda Paiste
  • 28,886
  • 4
  • 42
  • 71
  • 1
    Thank you for this, its my weekend project, so took longer to get it working. If I am honest, I got the core idea from your answer and there were some bits that helped me a lot when I used this [Freecodecamp blog](https://www.freecodecamp.org/news/how-to-get-started-with-gatsby-2-and-redux-ae1c543571ca/). Leaving it here for other readers, if they find it useful as I did. Thank you! – user3547204 Mar 06 '21 at 11:08
0

The answer posted already and the Freecodecamp link posted in the comment were both really helpful resources, however for my specific use case I found looking at the Gatsby repository on redux the most helpful": https://github.com/gatsbyjs/gatsby/tree/master/examples/using-redux

Also, I ended up realizing that sessionStorage was more appropriate for my use case as I was trying to store data beyond a page refresh and I wasn't using the other features Redux offered. You can read more about localStorage here: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage and the differences between Redux and local storage here: Why redux instead of session storage

Also if you're using Redux I highly reccomend the redux-devtools extension for debugging you can install the package here: https://www.npmjs.com/package/@redux-devtools/extension and the browser extension here: https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en