Skip to content
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

With Firebase Client-Side example #11053

Merged
merged 11 commits into from Mar 20, 2020
Merged
25 changes: 25 additions & 0 deletions examples/with-firebase-client-side/.gitignore
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
.env*

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
48 changes: 48 additions & 0 deletions examples/with-firebase-client-side/README.md
@@ -0,0 +1,48 @@
# With Firebase Client-Side

This is a simple set up for Firebase on the client side. It uses React Context to store some data about the state of your Firebase app. It's all client side, so no custom server.

## Deploy your own

Deploy the example using [ZEIT Now](https://zeit.co/now):

[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-firebase-client-side)

## How to use

### Using `create-next-app`

Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example with-firebase-client-side with-firebase-client-side-app
# or
yarn create next-app --example with-firebase-client-side with-firebase-client-side-app
```

### Download manually

Download the example:

```bash
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-firebase-client-side
cd with-firebase-client-side
```

Install it and run:

```bash
npm install
npm run dev
# or
yarn
yarn dev
```

### Setting up Firebase

- Create a [Firebase project](https://console.firebase.google.com/u/0/).
- Fill in your credentials at `/credentials/client`
- Done!

Deploy it to the cloud with [ZEIT Now](https://zeit.co/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
57 changes: 57 additions & 0 deletions examples/with-firebase-client-side/context/firebaseContext.js
@@ -0,0 +1,57 @@
import { useState, useEffect, createContext, useContext } from 'react'
import firebase from 'firebase/app'
import 'firebase/auth' // If you need it
import 'firebase/firestore' // If you need it
import 'firebase/storage' // If you need it
import 'firebase/analytics' // If you need it
import clientCredentials from '../credentials/client' // Your credentials

export const FirebaseContext = createContext()

export default ({ children }) => {
const [isInitialized, setIsInitialized] = useState(false)
const [user, setUser] = useState(null)
const [loadingUser, setLoadingUser] = useState(true) // Helpful, to update the UI accordingly.

useEffect(() => {
// Initialize Firebase
if (!firebase.apps.length) {
try {
firebase.initializeApp(clientCredentials)
// Analytics
if ('measurementId' in clientCredentials) firebase.analytics()
// Listen authenticated user
firebase.auth().onAuthStateChanged(async user => {
try {
if (user) {
// User is signed in.
const { uid, displayName, email, photoURL } = user
// You could also look for the user doc in your Firestore (if you have one):
// const userDoc = await firebase.firestore().doc(`users/${uid}`).get()
setUser({ uid, displayName, email, photoURL })
} else setUser(null)
} catch (error) {
// Most probably a connection error. Handle appropiately.
} finally {
setLoadingUser(false)
}
})
setIsInitialized(true)
} catch (error) {
// This error will be: Invalid API Key of something of that sort. Because you need to fill in your credentials!
console.error(error)
}
}
}, [])

return (
<FirebaseContext.Provider
value={{ isInitialized, user, setUser, loadingUser }}
>
{children}
</FirebaseContext.Provider>
)
}

// Custom hook that shorhands the context!
export const useFirebase = () => useContext(FirebaseContext)
28 changes: 28 additions & 0 deletions examples/with-firebase-client-side/credentials/client.js
@@ -0,0 +1,28 @@
// TODO: Fill in with your credentials
const productionCredentials = {
lfades marked this conversation as resolved.
Show resolved Hide resolved
apiKey: '',
authDomain: '<PROJECT_ID>.firebaseapp.com',
databaseURL: 'https://<PROJECT_ID>.firebaseio.com',
projectId: '<PROJECT_ID>',
storageBucket: '<PROJECT_ID>.appspot.com',
messagingSenderId: '',
appId: '',
}

export default productionCredentials

// If you have a staging project, you can do something like the following:
// const stagingCredentials = {
// apiKey: '',
// authDomain: '<PROJECT_ID>.firebaseapp.com',
// databaseURL: 'https://<PROJECT_ID>.firebaseio.com',
// projectId: '<PROJECT_ID>',
// storageBucket: '<PROJECT_ID>.appspot.com',
// messagingSenderId: '',
// appId: '',
// }

// let credentials = productionCredentials
// if (process.env.NODE_ENV !== 'production') credentials = stagingCredentials

// export default credentials
16 changes: 16 additions & 0 deletions examples/with-firebase-client-side/package.json
@@ -0,0 +1,16 @@
{
"name": "with-firebase-client-side",
"version": "0.1.0",
"private": true,
julianbenegas marked this conversation as resolved.
Show resolved Hide resolved
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"firebase": "7.11.0",
"next": "latest",
"react": "^16.13.0",
"react-dom": "^16.13.0"
}
}
8 changes: 8 additions & 0 deletions examples/with-firebase-client-side/pages/_app.js
@@ -0,0 +1,8 @@
import FirebaseProvider from '../context/firebaseContext'

// Custom App to wrap it with context provider
export default ({ Component, pageProps }) => (
<FirebaseProvider>
<Component {...pageProps} />
</FirebaseProvider>
)
186 changes: 186 additions & 0 deletions examples/with-firebase-client-side/pages/index.js
@@ -0,0 +1,186 @@
import Head from 'next/head'
import { useEffect } from 'react'
import { useFirebase } from '../context/firebaseContext'
import firebase from 'firebase/app'

export default () => {
// Our custom hook to get context values
const { isInitialized, loadingUser, user } = useFirebase()

useEffect(() => {
if (isInitialized) {
// You can use your firebase app here
// firebase.firestore().doc('whatever').get()
console.log(firebase)
if (!loadingUser) {
// You can know that the user is loaded: either logged in or out!
console.log(user)
}
}
}, [isInitialized, loadingUser, user])

return (
<div className="container">
<Head>
<title>Next.js w/ Firebase Client-Side</title>
<link rel="icon" href="/favicon.ico" />
</Head>

<main>
<h1 className="title">Next.js w/ Firebase Client-Side</h1>
<p className="description">Fill in your credentials to get started</p>
</main>

<footer>
<a
href="https://zeit.co?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by <img src="/zeit.svg" alt="ZEIT Logo" />
</a>
</footer>

<style jsx>{`
.container {
min-height: 100vh;
padding: 0 0.5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

footer {
width: 100%;
height: 100px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
}

footer img {
margin-left: 0.5rem;
}

footer a {
display: flex;
justify-content: center;
align-items: center;
}

a {
color: inherit;
text-decoration: none;
}

.title a {
color: #0070f3;
text-decoration: none;
}

.title a:hover,
.title a:focus,
.title a:active {
text-decoration: underline;
}

.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
}

.title,
.description {
text-align: center;
}

.description {
line-height: 1.5;
font-size: 1.5rem;
}

code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
}

.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
margin-top: 3rem;
}

.card {
margin: 1rem;
flex-basis: 45%;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
}

.card:hover,
.card:focus,
.card:active {
color: #0070f3;
border-color: #0070f3;
}

.card h3 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}

.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}

@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}
`}</style>

<style jsx global>{`
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
sans-serif;
}

* {
box-sizing: border-box;
}
`}</style>
</div>
)
}
Binary file not shown.
10 changes: 10 additions & 0 deletions examples/with-firebase-client-side/public/zeit.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.