Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ionic React 4.11 : How to Push and Pop in Navigation (IonNav)

I am new to Ionic. I just installed newly released Ionic React 4.11 (https://ionicframework.com/blog/announcing-ionic-react/) on my local system. But can not find proper documentation on some of the components.This document page doesn't contains any example of usage.

I need some help to implement Nav example shown in the below given link.

https://ionicframework.com/docs/api/nav

enter image description here

Can anyone please guide how can implement the same example in Ionic React.

I have found example code here : https://github.com/ionic-team/ionic-docs/blob/master/src/demos/api/nav/index.html

But it is in Plain JavaScript, So I tried to convert it in React format. but not sure about how can I convert the same example code in React. Only Pending part is to inject relative NavDetail component on click of any item. Please see attached screenshot how much I am able to achieve.

enter image description here

const techs = [
    {
        'title': 'Angular',
        'icon': 'angular',
        'description': 'A powerful Javascript framework for building single page apps. Angular is open source, and maintained by Google.',
        'color': '#E63135'
    },
    {
        'title': 'CSS3',
        'icon': 'css3',
        'description': 'The latest version of cascading stylesheets - the styling language of the web!',
        'color': '#0CA9EA'
    },
    {
        'title': 'HTML5',
        'icon': 'html5',
        'description': 'The latest version of the web\'s markup language.',
        'color': '#F46529'
    },
    {
        'title': 'JavaScript',
        'icon': 'javascript',
        'description': 'One of the most popular programming languages on the Web!',
        'color': '#FFD439'
    },
    {
        'title': 'Sass',
        'icon': 'sass',
        'description': 'Syntactically Awesome Stylesheets - a mature, stable, and powerful professional grade CSS extension.',
        'color': '#CE6296'
    },
    {
        'title': 'NodeJS',
        'icon': 'nodejs',
        'description': 'An open-source, cross-platform runtime environment for developing server-side Web applications.',
        'color': '#78BD43'
    },
    {
        'title': 'Python',
        'icon': 'python',
        'description': 'A clear and powerful object-oriented programming language!',
        'color': '#3575AC'
    },
    {
        'title': 'Markdown',
        'icon': 'markdown',
        'description': 'A super simple way to add formatting like headers, bold, bulleted lists, and so on to plain text.',
        'color': '#412159'
    },
    {
        'title': 'Tux',
        'icon': 'tux',
        'description': 'The official mascot of the Linux kernel!',
        'color': '#000'
    },
];

const NavHome = (props: any) => {
    const showDetail = (title: any): void => {
    alert('you clicked '+ title);
        // Need help to push item on click of list
        // const tech = techs.find(tech => tech.title === title);
        // nav.push('nav-detail', { tech });

    };

    return (
        <React.Fragment>
            <IonHeader translucent>
                <IonToolbar>
                    <IonTitle>Test 111</IonTitle>
                </IonToolbar>
            </IonHeader>

            <IonContent fullscreen class="ion-padding">
                <IonList>
                    {techs.map(tech =>
                        <IonItem button key={Math.random()} onClick={() => showDetail(tech.title)}>
                            <IonIcon slot="start" name="logo-${tech.icon}"></IonIcon>
                            <IonLabel>{tech.title}</IonLabel>
                        </IonItem>
                    )};
                </IonList>
            </IonContent>
        </React.Fragment>
    )
};

const NavDetail = () => (
    <React.Fragment>
        <IonHeader translucent>
            <IonToolbar>
                <IonButton slot="start">Back</IonButton>
                <IonTitle>Test</IonTitle>
            </IonToolbar>
        </IonHeader>
        <IonContent fullscreen class="ion-padding">
            <p>Hi</p>
        </IonContent>
    </React.Fragment>
);


const App: React.FC = () => (
    <IonApp>
        <IonReactRouter>

            <IonNav></IonNav>

            <NavHome />

        </IonReactRouter>
    </IonApp>
);

export default App;

Thanks, Jignesh Raval

like image 227
Jignesh Raval Avatar asked Oct 15 '22 10:10

Jignesh Raval


3 Answers

You can't use IonNav in react. I tried a lot to make it work but I couldn't. I don't know why it's there but it isn't usable as of today.

Even, Mike Hartington from the ionic-team said, "you do not use ion-nav in react".

You should just follow the official doc for navigation.

like image 116
Mark Avatar answered Oct 21 '22 05:10

Mark


As of today the ion-nav is still not officially supported in React, so I've played around with JS a bit to make it work (some of it is trial and error, so it might be a bit confusing). Inside my IonReactNav, I wrap and set the props.children as ion-nav root. I also expect the detail prop to be a function that renders my Detail component. I then create a nav-detail custom element and append the Detail nodes:

IonReactNav.tsx

import React from 'react';
import { IonNav } from '@ionic/react';

interface IonReactNavProps {
  detail: Function
}

const IonReactNav: React.FC<IonReactNavProps> = ({ children, detail }) => {

  const handleNavWillChange = async (navEl: HTMLIonNavElement) => {
    const rootView = await navEl.getByIndex(0)
    
    if (rootView === undefined) {
      const homeEl = navEl.querySelector('#home-wrapper') as HTMLDivElement
      const detailEl = navEl.querySelector('#detail-wrapper') as HTMLDivElement

      if (!homeEl || !detailEl) {
        throw new Error('Missing home or detail wrapper elements')
      }

      navEl.setRoot(homeEl)

      if (customElements.get('nav-detail') === undefined) {
        const detailNodes: ChildNode[] = []
        detailEl.childNodes.forEach(node => {
          detailNodes.push(node)
        })

        customElements.define('nav-detail', class NavDetail extends HTMLElement {
          connectedCallback() {
            this.append(...detailNodes)
          }
        })
      }

      navEl.querySelectorAll('.ion-react-nav-detail-btn').forEach(btn => {
        btn.addEventListener('click', function () {
          navEl.push('nav-detail')
        })
      })
    }
  }


  return (
    <IonNav onIonNavWillChange={(e) => handleNavWillChange(e.target as HTMLIonNavElement)} root="nav-home">
      <div id="home-wrapper" >
        {children}
      </div>
      <div id="detail-wrapper" style={{ display: 'none' }}>
        {detail()}
      </div>
    </IonNav>
  )
}

export default IonReactNav

I also expect the open detail button to have a ion-react-nav-detail-btn class, so I can attach the proper event inside IonReactNav.

<IonReactNav detail={() => <TechDetail {...tech} />}>
  ...
  <IonList>
    {techs.map((tech, i) => {
      return (
        <IonItem button className="ion-react-nav-detail-btn" key={i} onClick={() => setTech(techs[i])}>
          <IonIcon slot="start" icon={tech.icon} style={{ color: `${tech.color}` }} />
            <IonLabel>
              <h3>{tech.title}</h3>
            </IonLabel>
        </IonItem>
      )
    })}
  </IonList>
  ...
</IonReactNav>

Checkout live demo here or feel free to clone the github repo where I used the ionic react blank starter app.

like image 45
htmn Avatar answered Oct 21 '22 05:10

htmn


Their official doc for React Navigation - https://ionicframework.com/docs/react/navigation

like image 34
arif08 Avatar answered Oct 21 '22 06:10

arif08