Home > Blockchain >  How can I simply pass data from a component one page to a component on another page in React/Next.js
How can I simply pass data from a component one page to a component on another page in React/Next.js

Time:12-31

Sumary

I have a simple next.js app with two pages, index.js and results.js. The index page has two Location AutoComplete fields which return the address and LatLng of a location after a user selects it from the dropdown of reccomended locations. Once returned, this data is stored in a variable called markers on the index page. When the user clicks the Get Results button on the index page, I'm attempting to pass the address and LatLng data to the results page, so that the selected locations can be shown as a markers on the map.

Problem

I've been attempting to do this on and off for about a week now and I can't figure out how to achieve what I want. I feel that there should be a super simple way to do this but I just can't figure it out. I've tried things like:

  • Passing the data thorough request parameters on a button click, but the link is generated based on the variables value when the page renders rather than being updated when the variable is updated
  • Having the map on the same page as the location autocomplete and attempting to use state to automatically reload the map, which didn't seem to work at all for me
  • I've also looked into Redux but this seems to be way too complicated to simply pass an object/it's data from one page to another

My ideal solution is a simple way to pass the data from indext to results. It's probably also worth pointing out that I'm new to React/Next.js so I might be going about all of this the wrong way, and once this is working I'll also be adding in an API call to get directions between the two LatLng points which will also be displayed on the map on the results page.

Code

index.js (simplified)

{/* Import used next and style objects */ }
import Head from 'next/head'
import styles from '../styles/Home.module.css'

{/* Import react-bootstrap */ }
import { Container, Row, Col } from 'react-bootstrap'

{/* Import geosuggest */ }
import Geosuggest from 'react-geosuggest'

{/* Import used components */ }
import NavigationBar from '../components/NavigationBar'
import Footer from '../components/Footer'

{/* Import and use runtime vars for Google API */ }
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
const GoogleApiUrl = `https://maps.googleapis.com/maps/api/js?key=${publicRuntimeConfig.MAPS_JAVASCRIPT_API_KEY}&libraries=places`

export default function Home() {

  const markers = {
    from: {description: "", lat: 0, lng: 0},
    to: {description: "", lat: 0, lng: 0}
  }

  const onFromSuggestSelect = (suggest) => {
    console.log("New FROM location selected: \""   suggest.description   "\"");
    markers.from.description = suggest.description
    markers.from.lat = suggest.location.lat
    markers.from.lng = suggest.location.lng
  }

  const onToSuggestSelect = (suggest) => {
    console.log("New TO location selected: \""   suggest.description   "\"");
    markers.to.description = suggest.description
    markers.to.lat = suggest.location.lat
    markers.to.lng = suggest.location.lng
  }

  return (
    <div>
      <Head>
        <title>MyApp</title>
        <meta name="description" content="MyApp" />
        <link rel="icon" href="/favicon.ico" />
        <script src={GoogleApiUrl}></script>
      </Head>

      <NavigationBar/>

      <div className={styles.container}>
        <main>
          <Container>
            <Row className="text-center">
              <Col md={1}></Col>
              <Col md={5}><Geosuggest data-test-id="autocomplete-start-test" placeholder="From..." onSuggestSelect={onFromSuggestSelect} country="gb"  minLength="3" /></Col>
              <Col md={5}><Geosuggest data-test-id="autocomplete-end-test" placeholder="To..." onSuggestSelect={onToSuggestSelect} country="gb"  minLength="3" /></Col>
              <Col md={1}></Col>
            </Row>
          </Container>
        </main>

        <Footer/>

      </div>
    </div>
  )
}

results.js (simplified)

{/* Import used next and style objects */ }
import Head from 'next/head'
import styles from '../styles/Home.module.css'

{/* Import used react-bootstrap objects */ }
import { Container } from 'react-bootstrap'

{/* Import used components */ }
import NavigationBar from '../components/NavigationBar'
import Footer from '../components/Footer'
import Map from '../components/Map'

{/* Import and use runtime vars for Google API */ }
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
const GoogleApiUrl = `https://maps.googleapis.com/maps/api/js?key=${publicRuntimeConfig.MAPS_JAVASCRIPT_API_KEY}&libraries=places`

export default function Home() {

    const markers = {
        from: {description: "", lat: 0, lng: 0},
        to: {description: "", lat: 0, lng: 0}
      }

  return (
    <div>
      <Head>
        <title>MyApp</title>
        <meta name="description" content="MyApp" />
        <link rel="icon" href="/favicon.ico" />
        <script src={GoogleApiUrl}></script>
      </Head>

      <NavigationBar/>

      <div className={styles.container}>
        <main>
            <Container>
                {/* MARKERS NEEDS TO BE PASSED IN ON THE LINE BELOW */}
                <Map markers={markers}/> 
            </Container>
        </main>
      </div>
      
      <Footer/>

    </div>
  )
}

Map.js (component)

import React from "react"
import { GoogleMap, Marker } from "@react-google-maps/api"

export default class Map extends React.Component {
    render() {
        // Set the map to fill its container
        const containerStyle = { width: '500px', height: '500px' }
          
        // Set the map to show the entire UK on initial load
        const center = { lat: 54.476422, lng: -3.397340 }
        const zoom = 6

        // Return the map with the above defaults
        return(
            <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={zoom}>
                <Marker position={{ lat: this.props.markers.from.lat, lng: this.props.markers.from.lng }} />
                <Marker position={{ lat: this.props.markers.to.lat, lng: this.props.markers.to.lng }} />
            </GoogleMap>
        )
    }
}

CodePudding user response:

I think there are two questions here:

  1. How do I pass data between two NextJS pages?
  2. Why isn't my link updating when the suggest values are updated?

There are a few different ways you can pass data between pages, but the querystring params is probably the method I would use. Although I would not use the description in the querystring if possible. You can do this by using the NextJS <Link /> component

However, it appears you have tried something like this and the link is not updating. The reason for this is how the markers data is set. You have set this as a const in the component, which tells React not to monitor changes to this object. When onFromSuggestSelect fires, it updates the object properties and then... nothing. React thinks that there can't be any changes to the <Link /> as nothing has changed in the Parent.

This is why we have React State. If you change your markers const to instead use the useState hook, you should find that the implemented <link /> will update when the value is changed.

A word of warning; read the docs thoroughly if you have not used the useState hook before so that you understand how to implement this correctly.

I hope this solves your problem.

  • Related