-
Notifications
You must be signed in to change notification settings - Fork 3.2k
docs(react): show complete code context in the "Your First App" tutorial #4201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
joesphchang
wants to merge
47
commits into
ionic-team:main
Choose a base branch
from
joesphchang:react-firstapp-content
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,206
−662
Open
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
9955fd4
docs(component): added missing components
joesphchang d4c5cda
docs(components): updated descriptions on components
joesphchang aeead46
docs(react): show complete code context in the "Your FirstApp" tutorial
joesphchang 4ff6c31
docs(react): ran npm run lint and fixed spelling in docs
joesphchang 2f52971
Merge branch 'main' into react-firstapp-content
joesphchang 21cbe64
Merge branch 'main' into react-firstapp-content
thetaPC e361e12
docs(components): remove redundant
thetaPC 1e5819f
Merge branch 'react-firstapp-content' of github.com:joesphchang/ionic…
thetaPC 26ed242
Update docs/react/your-first-app.md
thetaPC 32b0976
docs(react): update your first app page
thetaPC e3410a2
docs(react): update file paths
thetaPC 2cefaad
docs(react): upate your first app page
thetaPC 7e9bb4d
docs(react): update taking photos page
thetaPC 290abfb
docs(react): update saving photos page
thetaPC a386a0c
docs(react): update loading photos page
thetaPC 6072689
docs(react): update adding mobile page
thetaPC cb2cdff
docs(react): update live reload page
thetaPC 978d7e6
docs(react): update your first app pages
thetaPC 9788859
docs(react): update your first app pages
thetaPC 524ad6a
docs(react): update your first app pages for v7
thetaPC 360a5da
docs(react): use readFile variable
thetaPC 52f3519
docs(react): use slice
thetaPC 90a1aca
docs(react): remove periods from comments
thetaPC 8b09582
docs(react): remove --capacitor
thetaPC 71914da
docs(react): update Ionic styles comment
thetaPC fb65b85
docs(react): use better title change example
thetaPC ea823a9
docs(react): add file path
thetaPC 80fb427
docs(react): remove redundant comment
thetaPC 7cea235
docs(react): better click event listener example
thetaPC 79fbfd4
docs(react): move existing code comment
thetaPC a13ce79
docs(react): update existing code comment
thetaPC ef8ae09
docs(react): add change comment
thetaPC 8544a57
docs(react): update syntax
thetaPC b3489b4
docs(react): update imports
thetaPC 6a96994
docs(react): remove first header
thetaPC a1152f7
docs(react): remove exclamation marks
thetaPC 4d26d98
docs(react): add Camera
thetaPC 8252e60
docs(react): update UserPhoto text
thetaPC 5f77afe
docs(react): update Filesystem path
thetaPC 2722fc6
docs(react): move note
thetaPC d9b9334
docs(react): add deployment text
thetaPC 809f727
docs(react): use proper grammar
thetaPC 7836499
chore(react): run lint
thetaPC 4bd4108
docs(react): add default App
thetaPC e0cd901
docs(react): update title of page 8
thetaPC 303fb12
docs(react): add default Tab2
thetaPC 49de97c
docs(react): remove fab code
thetaPC File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,10 +4,10 @@ sidebar_label: Build Your First App | |||||||||
| --- | ||||||||||
|
|
||||||||||
| <head> | ||||||||||
| <title>React Apps | Build Your First Ionic Framework React Application</title> | ||||||||||
| <title>Build Your First Ionic Mobile App with React | Ionic Capacitor Camera</title> | ||||||||||
| <meta | ||||||||||
| name="description" | ||||||||||
| content="Build your first Ionic React App. With one codebase, you can build an Ionic Framework application for any platform using just HTML, CSS, and JavaScript." | ||||||||||
| content="This React tutorial teaches the fundamentals of Ionic app development by creating a realistic app step-by-step. Learn to run your first Ionic app with React." | ||||||||||
| /> | ||||||||||
| </head> | ||||||||||
|
|
||||||||||
|
|
@@ -30,11 +30,11 @@ We'll create a Photo Gallery app that offers the ability to take photos with you | |||||||||
|
|
||||||||||
| Highlights include: | ||||||||||
|
|
||||||||||
| - One React-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](https://ionicframework.com/docs/components). | ||||||||||
| - One React-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](../components.md). | ||||||||||
| - Deployed as a native iOS and Android mobile app using [Capacitor](https://capacitorjs.com), Ionic's official native app runtime. | ||||||||||
| - Photo Gallery functionality powered by the Capacitor [Camera](https://capacitorjs.com/docs/apis/camera), [Filesystem](https://capacitorjs.com/docs/apis/filesystem), and [Preferences](https://capacitorjs.com/docs/apis/preferences) APIs. | ||||||||||
| - Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.md), [Filesystem](../native/filesystem.md), and [Preferences](../native/preferences.md) APIs. | ||||||||||
|
|
||||||||||
| Find the complete app code referenced in this guide [on GitHub](https://github.com/ionic-team/photo-gallery-capacitor-react). | ||||||||||
| Find the [complete app code](https://github.com/ionic-team/tutorial-photo-gallery-react) referenced in this guide on GitHub. | ||||||||||
|
|
||||||||||
| ## Download Required Tools | ||||||||||
|
|
||||||||||
|
|
@@ -43,9 +43,8 @@ Download and install these right away to ensure an optimal Ionic development exp | |||||||||
| - **Node.js** for interacting with the Ionic ecosystem. [Download the LTS version here](https://nodejs.org/en/). | ||||||||||
| - **A code editor** for... writing code! We are fans of [Visual Studio Code](https://code.visualstudio.com/). | ||||||||||
| - **Command-line interface/terminal (CLI)**: | ||||||||||
| - **Windows** users: for the best Ionic experience, we recommend the built-in command line (cmd) or the Powershell | ||||||||||
| CLI, running in Administrator mode. | ||||||||||
| - **Mac/Linux** users, virtually any terminal will work. | ||||||||||
| - **Windows** users: for the best Ionic experience, we recommend the built-in command line (cmd) or the Powershell CLI, running in Administrator mode. | ||||||||||
| - **Mac/Linux** users: virtually any terminal will work. | ||||||||||
|
|
||||||||||
| ## Install Ionic Tooling | ||||||||||
|
|
||||||||||
|
|
@@ -67,10 +66,10 @@ Consider setting up npm to operate globally without elevated permissions. See [R | |||||||||
|
|
||||||||||
| ## Create an App | ||||||||||
|
|
||||||||||
| Next, create an Ionic React app that uses the “Tabs” starter template and adds Capacitor for native functionality: | ||||||||||
| Next, create an Ionic React app that uses the "Tabs" starter template and adds Capacitor for native functionality: | ||||||||||
|
|
||||||||||
| ```shell | ||||||||||
| ionic start photo-gallery tabs --type=react --capacitor | ||||||||||
| ionic start photo-gallery tabs --type=react | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| This starter project comes complete with three pre-built pages and best practices for Ionic development. With common building blocks already in place, we can add more features easily! | ||||||||||
|
|
@@ -89,116 +88,212 @@ npm install @capacitor/camera @capacitor/preferences @capacitor/filesystem | |||||||||
|
|
||||||||||
| ### PWA Elements | ||||||||||
|
|
||||||||||
| Some Capacitor plugins, including the Camera API, provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). | ||||||||||
| Some Capacitor plugins, including the [Camera API](../native/camera.md), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). | ||||||||||
|
|
||||||||||
| It's a separate dependency, so install it next: | ||||||||||
|
|
||||||||||
| ```shell | ||||||||||
| npm install @ionic/pwa-elements | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| After installation, open up the project in your code editor of choice. | ||||||||||
|
|
||||||||||
| Next, import `@ionic/pwa-elements` by editing `src/main.tsx`. | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| import React from 'react'; | ||||||||||
| import { createRoot } from 'react-dom/client'; | ||||||||||
| import App from './App'; | ||||||||||
| // CHANGE: Add the following import | ||||||||||
| import { defineCustomElements } from '@ionic/pwa-elements/loader'; | ||||||||||
|
|
||||||||||
| // Call the element loader before the render call | ||||||||||
| // CHANGE: Call the element loader before the render call | ||||||||||
| defineCustomElements(window); | ||||||||||
|
|
||||||||||
| const container = document.getElementById('root'); | ||||||||||
| const root = createRoot(container!); | ||||||||||
| root.render( | ||||||||||
| <React.StrictMode> | ||||||||||
| <App /> | ||||||||||
| </React.StrictMode> | ||||||||||
| ); | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| That’s it! Now for the fun part - let’s see the app in action. | ||||||||||
|
|
||||||||||
| ## Run the App | ||||||||||
|
|
||||||||||
| Run this command in your shell: | ||||||||||
| Run this command next: | ||||||||||
|
|
||||||||||
| ```shell | ||||||||||
| ionic serve | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| And voilà! Your Ionic app is now running in a web browser. Most of your app can be built and tested right in the browser, greatly increasing development and testing speed. | ||||||||||
|
|
||||||||||
| ## Photo Gallery!!! | ||||||||||
| ## Photo Gallery | ||||||||||
|
|
||||||||||
| There are three tabs. Click on the Tab2 tab. It’s a blank canvas, aka the perfect spot to transform into a Photo Gallery. The Ionic CLI features Live Reload, so when you make changes and save them, the app is updated immediately! | ||||||||||
| There are three tabs. Click on the "Tab2" tab. It’s a blank canvas, aka the perfect spot to transform into a Photo Gallery. The Ionic CLI features Live Reload, so when you make changes and save them, the app is updated immediately! | ||||||||||
|
|
||||||||||
|  | ||||||||||
|
|
||||||||||
| Open `/src/pages/Tab2.tsx`. We see: | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react'; | ||||||||||
| import ExploreContainer from '../components/ExploreContainer'; | ||||||||||
| import './Tab2.css'; | ||||||||||
|
|
||||||||||
| const Tab2: React.FC = () => { | ||||||||||
| return ( | ||||||||||
| <IonPage> | ||||||||||
| <IonHeader> | ||||||||||
| <IonToolbar> | ||||||||||
| <IonTitle>Tab 2</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
| <IonContent fullscreen> | ||||||||||
| <IonHeader collapse="condense"> | ||||||||||
| <IonToolbar> | ||||||||||
| <IonTitle size="large">Tab 2</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
| <ExploreContainer name="Tab 2 page" /> | ||||||||||
| </IonContent> | ||||||||||
| </IonPage> | ||||||||||
| ); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| export default Tab2; | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| `IonHeader` represents the top navigation and toolbar, with "Tab 2" as the title (there are two of them due to iOS [Collapsible Large Title](../api/title.md#collapsible-large-titles) support). Let’s rename both `IonTitle` elements to: | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| <IonPage> | ||||||||||
| <IonHeader> | ||||||||||
| <IonToolbar> | ||||||||||
| <IonTitle>Tab 2</IonTitle> | ||||||||||
| {/* CHANGE: Update title */} | ||||||||||
| <IonTitle>Photo Gallery</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
| <IonContent> | ||||||||||
| <!-- some filler --> | ||||||||||
| <IonHeader collapse="condense"> | ||||||||||
| <IonToolbar> | ||||||||||
| {/* CHANGE: Update title */} | ||||||||||
| <IonTitle size="large">Photo Gallery</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
|
|
||||||||||
| {/* ...existing code... */} | ||||||||||
| </IonContent> | ||||||||||
| </IonPage> | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| `IonHeader` represents the top navigation and toolbar, with "Tab 2" as the title. Let’s rename it: | ||||||||||
| We put the visual aspects of our app into `<IonContent>`. In this case, it’s where we’ll add a button that opens the device’s camera as well as displays the image captured by the camera. Start by adding a [floating action button](../api/fab.md) (FAB) to the bottom of the page and set the camera image as the icon. | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| <IonTitle>Photo Gallery</IonTitle> | ||||||||||
| // CHANGE: Add the following import | ||||||||||
| import { camera } from 'ionicons/icons'; | ||||||||||
| // CHANGE: Update the following import | ||||||||||
| import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon } from '@ionic/react'; | ||||||||||
| // CHANGE: Remove or comment out `ExploreContainer` | ||||||||||
| // import ExploreContainer from '../components/ExploreContainer'; | ||||||||||
| import './Tab2.css'; | ||||||||||
|
|
||||||||||
| const Tab2: React.FC = () => { | ||||||||||
| return ( | ||||||||||
| <IonPage> | ||||||||||
| <IonHeader> | ||||||||||
| <IonToolbar> | ||||||||||
| <IonTitle>Photo Gallery</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
| <IonContent fullscreen> | ||||||||||
| <IonHeader collapse="condense"> | ||||||||||
| <IonToolbar> | ||||||||||
| <IonTitle size="large">Photo Gallery</IonTitle> | ||||||||||
| </IonToolbar> | ||||||||||
| </IonHeader> | ||||||||||
|
|
||||||||||
| {/* CHANGE: Add the floating action button */} | ||||||||||
| <IonFab vertical="bottom" horizontal="center" slot="fixed"> | ||||||||||
| <IonFabButton> | ||||||||||
| <IonIcon icon={camera}></IonIcon> | ||||||||||
| </IonFabButton> | ||||||||||
| </IonFab> | ||||||||||
|
|
||||||||||
| {/* CHANGE: Remove or comment out `ExploreContainer` */} | ||||||||||
| {/* <ExploreContainer name="Tab 2 page" /> */} | ||||||||||
| </IonContent> | ||||||||||
| </IonPage> | ||||||||||
| ); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| export default Tab2; | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| We put the visual aspects of our app into `<IonContent>`. In this case, it’s where we’ll add a button that opens the device’s camera as well as displays the image captured by the camera. Start by adding a [floating action button](https://ionicframework.com/docs/api/fab) (FAB). First, update the imports at the top of the page to include the Camera icon as well as some of the Ionic components we'll use shortly: | ||||||||||
| Next, open `src/App.tsx`. Change the label to "Photos" and the `ellipse` icon to `images` for the middle tab button. | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| import { camera, trash, close } from 'ionicons/icons'; | ||||||||||
| import { Redirect, Route } from 'react-router-dom'; | ||||||||||
| import { | ||||||||||
| IonContent, | ||||||||||
| IonHeader, | ||||||||||
| IonPage, | ||||||||||
| IonTitle, | ||||||||||
| IonToolbar, | ||||||||||
| IonFab, | ||||||||||
| IonFabButton, | ||||||||||
| IonApp, | ||||||||||
| IonIcon, | ||||||||||
| IonGrid, | ||||||||||
| IonRow, | ||||||||||
| IonCol, | ||||||||||
| IonImg, | ||||||||||
| IonActionSheet, | ||||||||||
| IonLabel, | ||||||||||
| IonRouterOutlet, | ||||||||||
| IonTabBar, | ||||||||||
| IonTabButton, | ||||||||||
| IonTabs, | ||||||||||
| setupIonicReact, | ||||||||||
| } from '@ionic/react'; | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| Then, add the FAB to the bottom of the page. Use the camera image as the icon, and call the `takePhoto()` function when this button is clicked (to be implemented soon): | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| <IonContent> | ||||||||||
| <IonFab vertical="bottom" horizontal="center" slot="fixed"> | ||||||||||
| <IonFabButton onClick={() => takePhoto()}> | ||||||||||
| <IonIcon icon={camera}></IonIcon> | ||||||||||
| </IonFabButton> | ||||||||||
| </IonFab> | ||||||||||
| </IonContent> | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| We’ll be creating the `takePhoto` method and the logic to use the Camera and other native features in a moment. | ||||||||||
|
|
||||||||||
| Next, open `src/App.tsx`, remove the `ellipse` icon from the import and import the `images` icon instead: | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| import { IonReactRouter } from '@ionic/react-router'; | ||||||||||
| // CHANGE: Update the following import | ||||||||||
| import { images, square, triangle } from 'ionicons/icons'; | ||||||||||
| import Tab1 from './pages/Tab1'; | ||||||||||
| import Tab2 from './pages/Tab2'; | ||||||||||
| import Tab3 from './pages/Tab3'; | ||||||||||
|
|
||||||||||
| /* ...existing Ionic styles... */ | ||||||||||
|
|
||||||||||
| const App: React.FC = () => ( | ||||||||||
| <IonApp> | ||||||||||
| <IonReactRouter> | ||||||||||
| <IonTabs> | ||||||||||
| <IonRouterOutlet> | ||||||||||
| <Route exact path="/tab1"> | ||||||||||
| <Tab1 /> | ||||||||||
| </Route> | ||||||||||
| <Route exact path="/tab2"> | ||||||||||
| <Tab2 /> | ||||||||||
| </Route> | ||||||||||
| <Route path="/tab3"> | ||||||||||
| <Tab3 /> | ||||||||||
| </Route> | ||||||||||
| <Route exact path="/"> | ||||||||||
| <Redirect to="/tab1" /> | ||||||||||
| </Route> | ||||||||||
| </IonRouterOutlet> | ||||||||||
| <IonTabBar slot="bottom"> | ||||||||||
| <IonTabButton tab="tab1" href="/tab1"> | ||||||||||
| <IonIcon aria-hidden="true" icon={triangle} /> | ||||||||||
| <IonLabel>Tab 1</IonLabel> | ||||||||||
| </IonTabButton> | ||||||||||
| <IonTabButton tab="tab2" href="/tab2"> | ||||||||||
| {/* CHANGE: Update icon */} | ||||||||||
| <IonIcon aria-hidden="true" icon={images} /> | ||||||||||
| {/* CHANGE: Update label */} | ||||||||||
| <IonLabel>Photos</IonLabel> | ||||||||||
| </IonTabButton> | ||||||||||
| <IonTabButton tab="tab3" href="/tab3"> | ||||||||||
| <IonIcon aria-hidden="true" icon={square} /> | ||||||||||
| <IonLabel>Tab 3</IonLabel> | ||||||||||
| </IonTabButton> | ||||||||||
| </IonTabBar> | ||||||||||
| </IonTabs> | ||||||||||
| </IonReactRouter> | ||||||||||
| </IonApp> | ||||||||||
| ); | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This is easy to remove accidentally during a copy/paste
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||
|
|
||||||||||
| export default App; | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| Within the tab bar (`<IonTabBar>`), change the label to “Photos” and the `ellipse` icon to `images` for the middle tab button: | ||||||||||
|
|
||||||||||
| ```tsx | ||||||||||
| <IonTabButton tab="tab2" href="/tab2"> | ||||||||||
| <IonIcon icon={images} /> | ||||||||||
| <IonLabel>Photos</IonLabel> | ||||||||||
| </IonTabButton> | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| :::note | ||||||||||
| In Ionic React, icons are imported individually from `ionicons/icons` and set to the icon prop. | ||||||||||
| ::: | ||||||||||
|
|
||||||||||
| That’s just the start of all the cool things we can do with Ionic. Up next, implement camera taking functionality on the web, then build it for iOS and Android. | ||||||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.