Quantcast
Channel: Ionic Framework - Ionic Forum
Viewing all articles
Browse latest Browse all 48981

Route to Mapbox only works once, but when I come back to it, nothing happens

$
0
0

I’m trying to learn Ionic and React I’m combining a Map app and a notes app and having it so I navigate with an IonToolbar.

I have the root go to the map. I click on the Notes app and it goes to the Notes app. When I go back to the Map, nothing shows up although I do see console logs and the url changes. There is also a component that allows you to add to Notes called Add. I can go back and forth between Notes and Add. But I can’t go back to Map. Any help will be appreciated. I’m a beginner so this is probably a basic question but any pointers would be helpful.

Here is my App.js

import { Redirect, Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet, IonTabButton, IonTabBar, IonLabel, IonIcon, IonTabs } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Map from './pages/Map';
import Notes from './pages/Notes';
import Add from './pages/Add';
import { triangle, ellipse, square } from 'ionicons/icons';

/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';

/* Basic CSS for apps built with Ionic */
import '@ionic/react/css/normalize.css';
import '@ionic/react/css/structure.css';
import '@ionic/react/css/typography.css';

/* Optional CSS utils that can be commented out */
import '@ionic/react/css/padding.css';
import '@ionic/react/css/float-elements.css';
import '@ionic/react/css/text-alignment.css';
import '@ionic/react/css/text-transformation.css';
import '@ionic/react/css/flex-utils.css';
import '@ionic/react/css/display.css';

/* Theme variables */
import './theme/variables.css';

function App () {

  return (
  <IonApp>
    <IonReactRouter>
      <IonTabs>
	      <IonRouterOutlet>
		<Route exact path="/map" component={Map}/>
		<Route exact path="/notes" component={Notes}/>
		<Route exact path="/add" component={Add}/>
		<Route exact path = "/" render={() => <Redirect to="/map"/>}/>
	      </IonRouterOutlet>
	      <IonTabBar slot='bottom'>
		<IonTabButton tab = 'Map' href='/map'>
		  <IonIcon icon={triangle} />
		  <IonLabel>Map</IonLabel>
		</IonTabButton>
		<IonTabButton tab = 'Notes' href='/notes'>
		  <IonIcon icon={square} />
		  <IonLabel>Notes</IonLabel>
		</IonTabButton>
	      </IonTabBar>
      </IonTabs>
    </IonReactRouter>
  </IonApp>
  );
}

export default App;

Here is my Map.js:

import ReactDOM from 'react-dom'
import React, { useRef, useEffect } from 'react';
import mapboxgl from 'mapbox-gl';
import '../App.css';
import fetchFakeData from '../api/fetchFakeData';
import Popup from '../components/Popup';




mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_ACCESS_TOKEN;

const App = () => {
  const mapContainerRef = useRef(null);
  const popUpRef = useRef(new mapboxgl.Popup({ offset: 15}));


  //initialize map when component mounts
  useEffect(() => {
    console.log("I'm here")
    const map = new mapboxgl.Map({
      container: mapContainerRef.current,
      // See style options here: https://docs.mapbox.com/api/maps/#styles
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [-104.9876, 39.7405],
      zoom: 12.5,
    });
    
    // add navigation control (the +/- zoom buttons)
    map.addControl(new mapboxgl.NavigationControl(), 'bottom-right');
    
    map.on('load', () => {
      // add the data source for new a feature collection with no features
      map.addSource('random-points-data', {
	type: 'geojson',
	data: {
	  type: 'FeatureCollection',
	  features: [],
	},

      });
      // now add the layer, and referece the data source above by name
      map.addLayer({
	id: 'random-points-layer',
	source: 'random-points-data',
	type: 'symbol',
	layout: {
	  // full list of icons here: https://labs.mapbox.com/maki-icons
	  'icon-image': 'bakery-15', //this will put little croissants on our map
	  'icon-padding':0,
	  'icon-allow-overlap': true,
	  },
	});
      });

    map.on('moveend', async () =>{
      //get new center coordinates
      const { lng, lat } = map.getCenter();
      // fetch new data
      const results = await fetchFakeData({ longitude: lng, latitude: lat });
      // update 'random-points-data' source with new data
      // all layers that consume the 'random-points-data' data source will be updated
      map.getSource('random-points-data').setData(results);
    });
    map.on('click', 'random-points-layer', e => {
      if (e.features.length) {
	const feature = e.features[0];
	// create popup node
	const popupNode = document.createElement('div');
	ReactDOM.render(<Popup feature={feature} />, popupNode);
	// set popup on map
	popUpRef.current.setLngLat(feature.geometry.coordinates).setDOMContent(popupNode).addTo(map);
      }
    });
    map.on('mouseenter', 'random-points-layer', e => {
      if (e.features.length) {
	map.getCanvas().style.cursor = 'pointer';
      }

    });

    // reset cursor to default when user is no longer hovering over a clickable feature
    map.on('mouseleave', 'random-points-layer', () => {
      map.getCanvas().style.cursor = '';
    });

    // clean up on unmount
    return () => map.remove();
  }, []); //eslint-disable-line react-hooks/exhaustive-deps

  return <div className='map-container' ref={mapContainerRef} />;
};


export default App;

and here is my Notes.js

import { IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCheckbox, IonCol, IonContent, IonFab, IonFabButton, IonGrid, IonHeader, IonIcon, IonItem, IonPage, IonRow, IonSlide, IonSlides, IonToolbar } from '@ionic/react';
import styles from './Notes.module.scss';

import { addOutline, menuOutline, notificationsOutline, searchOutline } from "ionicons/icons";
import { getCategories, getNotes } from '../store/Selectors';
import { CategoryStore, NoteStore } from '../store';
import { markNote } from "../store/NoteStore";

const Notes = () => {

	const categories = CategoryStore.useState(getCategories);
	const notes = NoteStore.useState(getNotes);

	const getNoteStyle = (categoryID, isComplete = false) => {

		const categoryColor = categories.filter(category => category.id === categoryID)[0].color;

		return {

			"--background": categoryColor,
			"--background-checked": categoryColor,
			"--border-style": "none",
			"opacity": isComplete ? "0.6" : "1"
		}
	}

	return (
		<IonPage>
			<IonHeader>
				<IonToolbar>
					<IonButtons slot="start">
						<IonButton>
							<IonIcon icon={ menuOutline } />
						</IonButton>
					</IonButtons>

					<IonButtons slot="end">
						<IonButton>
							<IonIcon icon={ searchOutline } />
						</IonButton>

						<IonButton>
							<IonIcon icon={ notificationsOutline } />
						</IonButton>
					</IonButtons>
				</IonToolbar>
			</IonHeader>
			<IonContent fullscreen>

				<IonGrid>
					<IonRow>
						<IonCol size="12" className="ion-padding-start">
							<h1 className={ styles.mainTitle }>Hello, Alan!</h1>
						</IonCol>
					</IonRow>

					<IonRow>
						<IonCol size="12" className="ion-padding-start ion-padding-top">
							<IonCardSubtitle className={ styles.heading }>
								Categories
							</IonCardSubtitle>
						</IonCol>
					</IonRow>
				</IonGrid>

				<IonSlides id="slider" options={{ slidesPerView: "auto", zoom: true, grabCursor: true }} className={ `${ styles.categorySlider } ion-padding-bottom` }>
					{ categories.map((category, index) => {

						const noteCount = notes.filter(n => n.category_id === category.id).length;

						return (

							<IonSlide key={ `categorySlide_${ index }`}>
								<IonCol className="ion-text-left">
									<IonCard>
										<IonCardHeader className="ion-no-padding">

											<div className={ styles.slideCount }>
												<h6>{ noteCount } { noteCount === 1 ? "note" : "notes" } </h6>
											</div>
											<div className={ styles.slideHeader }>
												<h4>{ category.name }</h4>
											</div>
										</IonCardHeader>

										<IonCardContent>
											<div className={ styles.categoryColor } style={{ borderBottom: `2px solid ${ category.color }` }}></div>
										</IonCardContent>
									</IonCard>
								</IonCol>
							</IonSlide>
						);
					})}
				</IonSlides>

				<IonGrid className={ styles.bottomContainer }>
					<IonRow>
						<IonCol size="12" className="ion-padding-start">
							<IonCardSubtitle className={ styles.heading }>
								Recent Notes
							</IonCardSubtitle>
						</IonCol>
					</IonRow>
					
					<div className={ styles.recentNotes }>

						{ notes.map((note, index) => {

							return (

								<IonRow key={ `note_${ index }` } className="animate__animated animate__faster" id={ `noteRow_${ note.id }` }>
									<IonCol size="12">
										<IonItem>
											<IonCheckbox checked={ note.complete } style={ getNoteStyle(note.category_id, note.complete) } onClick={ () => markNote(note.id) } />
											<h4 style={ note.complete ? { textDecoration: "line-through", opacity: "0.6" } : {} }>{ note.note }</h4>
										</IonItem>
									</IonCol>
								</IonRow>
							);
						})}
					</div>
				</IonGrid>

				<IonFab vertical="bottom" horizontal="end" slot="fixed" className="ion-padding">
					<IonFabButton routerLink="/add">
						<IonIcon icon={ addOutline } />
					</IonFabButton>
				</IonFab>
			</IonContent>
		</IonPage>
	);
};

export default Notes;

I hope I’m explaining myself, please let me know if any more of my code needs to be shown. Thanks for reading.

1 post - 1 participant

Read full topic


Viewing all articles
Browse latest Browse all 48981

Trending Articles