Search code examples
javascriptreactjscomponents

Export two constants from one component to another


So im trying to export the two constants latitude and longitude to another component, its not a child or parent of the component with the constants in so I cannot use context or props. I tried exporting as a named variable but because the constants are defined within the Header component they are out of scope for the export statements. Someone please fix this for me, Im going to cry if i spend anymore time trying to fix it.

import React, { useState } from 'react';
import axios from 'axios'; 

function Header() {

    const [text, setText] = useState("");
    const [latitude, setLatitude] = useState(0);
    const [longitude, setLongitude] = useState(0);


    function handleChange(event) {
        setText(event.target.value);
    }

    function handleClick() {
        const geoCoderURL = "http://api.openweathermap.org/geo/1.0/direct?q=" + text + "&limit=5&appid={apikey}"
        function getCoordinates(url) {
            axios.get(url).then((response) => {
                setLatitude(response.data[0].lat);
                setLongitude(response.data[0].lon);
            });
        } 
        getCoordinates(geoCoderURL);        
    }

    return (
        <div>
            <h1>Five Day Forecast</h1> 
            <input onChange={handleChange} type="text" name="name" autoFocus placeholder="Enter location here."/>
            <button type="submit" onClick={handleClick}>Forecast</button> 
        </div>
    )
}

export const locationLat = latitude;
export const locationLon = longitude;
export default Header;



Solution

  • This is a basic setup of a Context. This particular example shows the creation of a context, a wrapper that holds the state inside the context, and a custom hook to access the context values from any component.

    The provider component looks just like a regular component except for the Context.Provider part. This is the part of the context that exposes the values of the context to its descendants.

    // coordinates-context.js
    import { createContext, useContext, useState } from 'react';
    
    /**
     * Create a new context.
     */
    const CoordinatesContext = createContext();
    
    /**
     * Create a provider wrapper which is responsible for the state 
     * and children of the context. In a lot of ways it works just like
     * a normal component, except for the Provider part, which is special
     * for the Context API.
     */
    export const CoordinatesProvider = ({ children }) => {
      const [coordinates, setCoordinates] = useState({ lat: null, lng: null });
    
      return (
        <CoordinatesContext.Provider value={[coordinates, setCoordinates]}>
          {children}
        </CoordinatesContext.Provider>
      );
    };
    
    /**
     * This custom hook will allow us you use the context in any component.
     */
    export const useCoordinatesContext = useContext(CoordinatesContext);
    

    The provider component should have the components that need the data as descendants, like the example below.

    <App>
      <CoordinatesProvider>
        <Header/>
        <OtherComponent/>
      </CoordinatesProvider>
    </App>
    

    Now that all the descendants have access, we can use the custom hook to use and manipulate the exposed values.

    Our context simply exposes a state, so the implementation works just like how you would use a useState hook.

    The only difference now is that all components that use the context, will be updated whenever any component updates the state inside of the context.

    import React, { useState } from 'react';
    import { useCoordinatesContext } from '../your-path-to/coordinates-context.js';
    import axios from 'axios'; 
    
    function Header() {
      const [text, setText] = useState("");
    
      /**
       * The hook exposes the useState values from the context provider.
       */
      const [coordinates, setCoordinates] = useCoordinatesContext();
    
      function handleChange(event) {
        setText(event.target.value);
      }
    
      function handleClick() {
        const geoCoderURL = "http://api.openweathermap.org/geo/1.0/direct?q=" + text + "&limit=5&appid={apikey}";
    
        function getCoordinates(url) {
          axios.get(url).then((response) => {
    
            /**
             * Update context state.
             */
            setCoordinates({
              lat: response.data[0].lat,
              lng: response.data[0].lon
            });
          });
        } 
        getCoordinates(geoCoderURL);        
      }
    
      return (
        <div>
          <h1>Five Day Forecast</h1> 
          <input onChange={handleChange} type="text" name="name" autoFocus placeholder="Enter location here."/>
          <button type="submit" onClick={handleClick}>Forecast</button> 
        </div>
      );
    }