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

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.