1

I'm new to Gatsby & React and I'm trying to figure out how to get the best of both worlds of prerendering and dynamic data.

The query alone works great for getting the data at build time and passing it as a prop to the Menu component where each menu item is rendered. However, at run time, I would like to pull the data again from the DB and have it update the data, for example, if there was a price change, etc.

I know I could just rebuild the whole project but I would like to have this as a fallback.

How can I make the query send the data to the Menu component and then also [send the data again?] when the DB call is done.

Code that is currently not working as expected:

index.jsx

import React, { useEffect } from "react"

import Layout from "../components/layout"
import SEO from "../components/seo"

import Menu from '../components/menu'
import { graphql } from "gatsby"

import firebase from "gatsby-plugin-firebase"
const IndexPage = (props) => {



  useEffect(() => {
    // use this hook to make db call and re-render menu component with most up to date data

    var db = firebase.firestore();
    let docs = []
    db.collection(`public/menu/${process.env.restaurantId}`).get().then(val => {

      val.forEach(doc => {
        docs.push({ node: doc.data() })
      });
      console.log('docs', docs)
      props.data.allMenuItem.edges = docs;  // i have no idea what i'm doing
    })


  }, [])


  return (
    <Layout>
      <SEO title="Home" />
      <Menu menuItems={props.data.allMenuItem.edges}></Menu>
    </Layout>
  )
}

// use this query for prerendering menu items
export const query = graphql`
query MyQuery   {
  allMenuItem {
    edges {
      node {
        available
        name
        group
      }
    }
  }
}
`;

export default IndexPage
Hamada
  • 1,836
  • 3
  • 13
  • 27
Marcus Gallegos
  • 1,532
  • 1
  • 16
  • 31

1 Answers1

2

You aren't supposed to modify React properties; any value that can change should be part of the state of the component. See Can I update a component's props in React.js?

However, the following code ought to do it. Create a state and give it the property value as default value. Then update it after the data loads on the client side.

const IndexPage = props => {
  const [menuItems, setMenuItems] = useState(props.data.allMenuItem.edges.map(({node}) => node))

  useEffect(() => {
    // use this hook to make db call and re-render menu component with most up to date data
    let db = firebase.firestore()

    db.collection(`public/menu/${process.env.restaurantId}`)
      .get()
      .then(setMenuItems)
  }, [])

  return (
    <Layout>
      <SEO title="Home" />
      <Menu menuItems={menuItems}></Menu>
    </Layout>
  )
}

Note that I've switched to using the data format you get from firestore (without node) rather than the one from Gatsby, so you'd need to modify your Menu component to not expect an extra level of nesting (with node) if you use this code.

ehrencrona
  • 6,102
  • 1
  • 18
  • 24
  • Thank you, this is a very clean solution! I tried implementing it and kept getting an infinite loop and realized the empty array in useEffect. – Marcus Gallegos Jul 14 '20 at 23:40