SlideShare uma empresa Scribd logo
1 de 50
Baixar para ler offline
1
Desenvolvimento de Software para WEB
Redux-Firebase-Authentication
2
Introdução
●
Neste projeto, iremos implementar uma aplicação de cadastro (signup), login
(signin) e logout, fazendo uso do firebase authentication para gerenciar
usuários e senhas.
●
O seu projeto irá necessitar das seguintes bibliotecas:
– "firebase": "^7.14.4" → Acesso à API do Firebase. É necessário ter conta no Google
– "redux": "^4.0.5" → Redux “puro”
– "react-redux": "^7.2.0" → “Cola” entre o React e o Redux
– "react-redux-firebase": "^3.5.1" → “Cola” entre o React, Redux e Firebase
– "react-router-dom": "^5.1.2" → Gerenciador de rotas
– "redux-thunk": "^2.3.0" → Middleware reponsável por ações assíncronas
3
Firebase Authentication
●
Crie um projeto no Firebase e vá em
Authentication:
4
Firebase Authentication
●
Na forma de login, escolha por e-mail/senha
5
Firebase Authentication
●
Em configurações do projeto, crie uma
aplicação WEB para acessar o projeto e copie
a chave de autenticação a ser colocada no
arquivo javascript do seu projeto.
6
O Projeto React
●
Uma vez instaladas as bibliotecas, crie o
seguinte esquema de pastas:
7
Conexão com o Firebase
●
Na pasta keys, crie o arquivo firebase_key.js:
const firebase_key = {
apiKey: "SDdsddkse8dsd-WlGeik_sdsdsdeeEEEsssddsd",
authDomain: "pet-redux-auth.firebaseapp.com",
databaseURL: "https://pet-dsdsdsds-dsd.dsdddd.com",
projectId: "pet-sdsddsd-authksdsdeeedusyd",
StorageBucket: "????",
messagingSenderId: "0000000000",
appId: "1sldjslue!!!sdssdsdsd:webskdhksds23033fa13315219d685e7a"
}
export default firebase_key
8
Conexão com Firebase
●
Na pasta utils, crie o arquivo firebase.js
import firebase from 'firebase/app'
import 'firebase/auth'
import firebase_key from '../keys/firebase_key'
firebase.initializeApp(firebase_key)
export default firebase
9
Conexão com Firebase
●
Note que o arquivo firebase.js usa o arquivo
firebase_key.js, para poder fazer a conexão
com o Firebase.
●
Você deve ter criado um projeto no Firebase e
um aplicação WEB, gerando assim a chave de
conexão.
10
Reducers
●
Os reducers, armazenam o estado geral da aplicação de uma
determinada entidade do domínio da aplicação. No nosso caso,
iremos armazenar a mensagem gerada pelas operações de
cadastro, login e logout.
●
Cada reducer é um função que recebe como parâmetro um state
(estado geral anterior) e uma action (ação).
●
Na pasta reducers iremos criar:
– authReducer.js (redutor reponsável pela autiorização)
– Index.js (estado geral da aplicação, a combinação de todos os redutores)
11
authReducer.js
import { SIGNUP_SUCCESS, SIGNUP_ERROR, SIGNIN_SUCCESS,
SIGNIN_ERROR, SIGNOUT_SUCCESS, SIGNOUT_ERROR }
from '../actions/actionTypes'
const INITIAL_STATE = {
authMsg: null,
user: ''
}
export default function (state = INITIAL_STATE, action) {
console.log('action: ' + action.type + ' ' + state.user)
switch (action.type) {
case SIGNUP_SUCCESS:
return {
...state,
authMsg: action.payload.authMessage,
user: action.payload.userMail,
}
case SIGNUP_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
case SIGNIN_SUCCESS:
return {
...state,
authMsg: action.payload.authMessage,
user: action.payload.userMail,
}
case SIGNIN_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
case SIGNOUT_SUCCESS:
return {
user: null,
authMsg: action.payload.authMessage
}
case SIGNOUT_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
default:
return state
}
}
Atenção! O arquivo actionTypes.js deve ser
Criado antes.
Atenção! Cada “case” trata de um tipo de action diferente. Lembre-se: toda vez que o usuário
Der um refresh na página (F5), o estado é resetado para o inicial.
Para este exemplo, iremos armazenar apenas
a mensagem de resultado de uma ação “authMsg”
e “user”, o qual armazera o e-mail logado.
12
index.js
import {combineReducers} from 'redux'
import authReducer from './authReducer'
import { firebaseReducer } from 'react-redux-firebase'
/* ESTADO GERAL DA APLICAÇÃO */
export default combineReducers({
firebaseReducer,
authReducer
})
Temos dois redutores (reducers) declarados neste arquivo: “firebaseReducer”, definido pela biblioteca
react-redux-firebase; e “authReducer”, criado por nós para guardar informações do usário logado.
13
Actions
●
As ações são disparadas de acordo com eventos da interface do usuário (navegador).
●
As ações podem alterar o estado geral da aplicação (definido em reducers/index.js), acionando os
redutores (que escolhem qual ação irão computar).
●
Cada ação tem um tipo (type) e um payload (informações do novo estado).
●
No nosso projeto, dentro da pastas actions, temos:
– actionTypes.js (arquivo simples de constantes)
– authActionCreator.js (criador de ações)
●
Na verdade, as ações são objetos simples em javascript ( {type,payload}). O arquivo
authActionCreator é formado por três funções (action creators) responsáveis em retornar uma ação. São
elas:
– signin (email,passwor,callback) → A função de login
– signup (email,passwor,callback) → A função de cadastro
– signout () → A função de logout
14
actionType.js
export const SIGNUP_SUCCESS = 'SIGNUP_SUCCESS'
export const SIGNUP_ERROR = 'SIGNUP_ERROR'
export const SIGNIN_SUCCESS = 'SIGNIN_SUCCESS'
export const SIGNIN_ERROR = 'SIGNIN_ERROR'
export const SIGNOUT_SUCCESS = 'SIGNOUT_SUCCESS'
export const SIGNOUT_ERROR = 'SIGNOUT_ERROR'
Define um conjunto de constantes que facilita e padroniza o uso das ações, evitando
erros de grafia.
15
authActionCreator.js
signup
import {SIGNUP_SUCCESS,SIGNUP_ERROR,SIGNIN_SUCCESS,SIGNIN_ERROR,SIGNOUT_SUCCESS,SIGNOUT_ERROR} from
'./actionTypes'
import firebase from '../../utils/firebase'
export const signup = (email,password,callback) => {
return dispatch =>{
try{
firebase
.auth()
.createUserWithEmailAndPassword(email,password)
.then(
()=>{
firebase.auth().onAuthStateChanged(
(user)=>{
if(user){
dispatch({
type:SIGNUP_SUCCESS,
payload: {
authMessage: `Cadastro efetuado com sucesso!`,
userMail: user.email}
})
callback()
}else{
dispatch({
type:SIGNUP_ERROR,
payload: {authMessage: `Não foi possível conectar`}
})
callback()
}
}
)//firebase.auth().onAuthStateChanged(
}//se deu certo
)
Atenção! Diferente do Redux usual, as nossas funções
não retornam apenas um objeto referente a ação, e sim
uma função: dispatch=>{ } .
Isso se deve graças a Middleware redux-thunk, pois no
caso de signin, signout e signup temos operações
assíncronas.
Para tratar operações assíncronas, o redux-thunk envolve
as ações {type, payload} dentro da função dispatch=>{},
possibilitando assim que sua aplicação não “trave” ao
fazer uma chamada remota ao Firebase.
16
authActionCreator.js
signup
.catch(
(error)=>{
dispatch({
type: SIGNUP_ERROR,
payload: {authMessage:`Erro na criação do usuário: ${error}`}
})
callback()
}
)
}catch(error){
dispatch({
type: SIGNUP_ERROR,
payload: { authMessage: `Erro na conexão com o firebase: ${error}`}
})
callback()
} //try-catch
} //return dispatch
}
A função callback(), passada como parâmetro, possibilita aos componentes que
chamarem essas ações “esperarem” dentro do callback a computação remota
acabar. Isto pode ser interessante em casos que a interface remota queira renderizar
uma tela de loading, que só fecha quando o resultado remoto é obtido.
Veremos mais detalhes do uso do callback no signin e signup, na interface.
17
authActionCreator.js
signin
export const signin = (email,password,callback) =>{
return dispatch => {
try{
firebase
.auth()
.signInWithEmailAndPassword(email,password)
.then(
(data)=>{
dispatch({
type: SIGNIN_SUCCESS,
payload: {
authMessage:`Login efetuado com sucesso`,
userMail: data.user.email}
})
callback()
}
)
.catch(
(error)=>{
dispatch({
type: SIGNIN_ERROR,
payload: {authMessage:`Erro login do usuário: ${error}`}
})
callback()
}
)
A lógica do Signin não é muito diferente de Signout.
18
authActionCreator.js
signin
}catch(error){
dispatch({
type: SIGNIN_ERROR,
payload: { authMessage: `Erro na conexão com o firebase: ${error}`}
})
callback()
}
}
}
19
authActionCreator.js
signout
export const signout = (callback) => {
return dispatch => {
try{
firebase
.auth()
.signOut()
.then(
()=>{
dispatch({
type: SIGNOUT_SUCCESS,
payload: {authMessage:`Signout efetuado com sucesso`}
})
callback()
}
)
.catch(
(error)=>{
dispatch({
type: SIGNOUT_ERROR,
payload: {authMessage:`Erro logout: ${error}`}
})
callback()
}
)
20
authActionCreator.js
signout
}catch(error){
dispatch({
type: SIGNOUT_ERROR,
payload: { authMessage: `Erro na conexão com o firebase: ${error}`}
})
callback()
}
}
}
21
Componentes Auxiliares
●
Dentro da pasta commons, iremos criar dois
componentes de interface auxiliares:
– Card.jsx → Acesso irrestrito
– RestrictedCard.jsx → Acessível apenas com o
usuário logado
22
Card.jsx
import React, { Component } from 'react'
export default class Card extends Component {
render() {
return (
<div className='content'>
<div className='card'>
<div className='card-header'>
{this.props.title}
</div>
<div className='card-body'>
{this.props.children}
</div>
</div>
</div>
)
}
}
Usa os “cards” do bootstrap. Mais detalhes em
https://getbootstrap.com/docs/4.3/components/card/
23
RestrictedCard.jsx
import React, {Component} from 'react'
import Card from './Card'
import { connect } from 'react-redux'
class RestrictedCard extends Component{
componentDidMount(){
if(this.props.firebaseAuth.isLoaded && this.props.firebaseAuth.isEmpty){
this.props.history.push('/signin')
}
}
render(){
return (
<Card title={this.props.title}>
{this.props.children}
</Card>
)
}
}
function mapStateToProps(state) {
return {
firebaseAuth: state.firebaseReducer.auth
}
}
export default connect(mapStateToProps)(RestrictedCard)
Agora, fazendo uso do redutor do firebase, definido em reducers/index.js, eu
Testo se o usuário ainda está logado.
24
Colando o Redux
●
Para inserir o Redux, temos que criar os
objetos no arquivo principal da aplicação, o
index.js de src.
●
Você deve seguir o que diz a documentação:
– http://react-redux-firebase.com/docs/v3-migration-g
uide.html
25
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import { ReactReduxFirebaseProvider} from 'react-redux-firebase'
import reduxThunk from 'redux-thunk'
import reducer from './store/reducers' //chamando index.js
import firebase from './utils/firebase'
const store = createStore(
reducer,
{},
applyMiddleware(reduxThunk)
)
const rrfProps = {
firebase,
config: {},
dispatch: store.dispatch
}
ReactDOM.render(
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<App />
</ReactReduxFirebaseProvider>
</Provider>
, document.getElementById('root')
);
serviceWorker.unregister();
Cria o estado geral e aplica a middleware, que trata de comunição assíncrona.
Configurações gerais do Firebase, usadas pelo “react-redux-firebase”
26
Componentes da Aplicação
●
Os componentes da aplicação são:
– Main.jsx → Apenas pra encher linguiça, escreva
qualquer coisa.
– Signinjsx → Login
– Signup.jsx → Cadastro
– Content A e B .jsx →páginas de acesso restrito
– App.jsx → Página raiz
27
App.jsx
import React, { Component } from 'react'
import { BrowserRouter, Link, Switch, Route } from 'react-router-dom'
import Main from './components/Main'
import Signin from './components/Signin'
import Signup from './components/Signup'
import ContentA from './components/ContentA'
import ContentB from './components/ContentB'
import { connect } from 'react-redux'
class App extends Component {
render() {
return (
<BrowserRouter>
<div className='container'>
<nav className='navbar navbar-expand-lg navbar-light bg-light'>
<Link to={'/'} className='navbar-brand'>PET Firebase Auth</Link>
<div className='collapse navbar-collapse' id='navbarSupportedContent'>
<ul className='navbar-nav mr-auto'>
<li>
<Link to={'/'} className='nav-link'>Home</Link>
</li>
<li>
<Link to={'/signin'} className='nav-link'>Login</Link>
</li>
<li>
<Link to={'/signup'} className='nav-link'>Cadastrar</Link>
</li>
<li>
<Link to={'/contentA'} className='nav-link'>Conteúdo A</Link>
</li>
<li>
<Link to={'/contentB'} className='nav-link'>Conteúdo B</Link>
</li>
</ul>
{this.props.user}
</div>
</nav>
<Switch>
<Route exact path='/' component={Main}/>
<Route path='/signin' component={Signin}/>
<Route path='/signup' component={Signup}/>
<Route path='/contentA' component={ContentA}/>
<Route path='/contentB' component={ContentB}/>
</Switch>
</div>
</BrowserRouter>
)
}
}
function mapStateToProps(state){
return{
user: state.authReducer.user
}
}
export default connect(mapStateToProps)(App)
Importando os componentes.
Imprimindo o valor da variável do estado geral, “user”.
28
Signup.jsx
(Cadastrar)
import React, { Component } from 'react'
import Card from './commons/Card'
import { connect } from 'react-redux'
import { signup } from '../store/actions/authActionCreator'
class Signup extends Component {
constructor(props) {
super(props)
this.state = { login: '', password: '' }
this.setLogin = this.setLogin.bind(this)
this.setPassword = this.setPassword.bind(this)
this.onSubmit = this.onSubmit.bind(this)
this._isMounted = false
}
componentDidMount(){
this._isMounted = true
}
componentWillUnmount(){
this._isMounted = false
}
setLogin(e) {
this.setState({ login: e.target.value })
}
setPassword(e) {
this.setState({ password: e.target.value })
}
29
Signup.jsx
(Cadastrar)
onSubmit(e) {
e.preventDefault()
this.setState({loading:true})
this.props.mySignup(this.state.login, this.state.password, ()=>{
this._isMounted && this.setState({loading:false})
})
this.setState({ login: '', password: ''})
}
renderButton() {
if (this.state.loading) {
return (
<button className="btn btn-primary" type="button" disabled>
<span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Carregando...
</button>
)
}
return (
<input type='submit' value='Cadastrar' className='btn btn-primary' />
)
}
renderMessage() {
if (this.props.userMsg) {
const msgType = (this.props.userMsg.includes('Err') ? 'alert-danger' : 'alert-info')
return (
<div className={`alert ${msgType}`} style={{ marginTop: '10px' }}>
{this.props.userMsg}
</div>
)
}
return
}
A implementação da função callback só será chamada quando a operação remota terminar.
30
Signup.jsx
(Cadastrar)
render() {
return (
<Card title='Cadastrar'>
<form onSubmit={this.onSubmit}>
<div className='form-group'>
<label>Login: </label>
<input type='text' className='form-control'
value={this.state.login} onChange={this.setLogin} />
</div>
<div className='form-group'>
<label>Password: </label>
<input type='password' className='form-control'
value={this.state.password} onChange={this.setPassword} />
</div>
{this.renderButton()}
</form>
{this.renderMessage()}
</Card>
)
}
}
function mapStateToProps(state) {
return {
userMsg: state.authReducer.authMsg
}
}
function mapDispatchToProps(dispatch) {
return {
mySignup(login, password,callback) {
const action = signup(login, password,callback)
dispatch(action)
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Signup)
31
Signin.jsx
(Fazer login)
import React, {Component} from 'react'
import Card from './commons/Card'
import { connect } from 'react-redux'
import { signin } from '../store/actions/authActionCreator'
class Signin extends Component{
constructor(props){
super(props)
this.state = {login:'',password:'',loading:false}
this.setLogin = this.setLogin.bind(this)
this.setPassword = this.setPassword.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
setLogin(e){
this.setState({login:e.target.value})
}
setPassword(e){
this.setState({password:e.target.value})
}
renderButton() {
if (this.state.loading) {
return (
<button className="btn btn-primary" type="button" disabled>
<span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Carregando...
</button>
)
}
return (
<input type='submit' value='Efetuar Login' className='btn btn-primary' />
)
}
32
Signin.jsx
(Fazer login)
renderMessage() {
if (this.props.userMsg) {
const msgType = (this.props.userMsg.includes('Err') ? 'alert-danger' : 'alert-info')
return (
<div className={`alert ${msgType}`} style={{ marginTop: '10px' }}>
{this.props.userMsg}
</div>
)
}
return
}
onSubmit(e){
e.preventDefault()
this.setState({loading:true})
this.props.mySignin(this.state.login,this.state.password, ()=>{
this.setState({loading:false})
})
this.setState({login:'',password:''})
}
33
Signin.jsx
(Fazer login)
render(){
return (
<Card title='Fazer Login'>
<form onSubmit={this.onSubmit}>
<div className='form-group'>
<label>Login: </label>
<input type='text' className='form-control'
value={this.state.login} onChange={this.setLogin} />
</div>
<div className='form-group'>
<label>Password: </label>
<input type='password' className='form-control'
value={this.state.password} onChange={this.setPassword} />
</div>
{this.renderButton()}
</form>
{this.renderMessage()}
</Card>
)
}
}
function mapStateToProps(state) {
return {
userMsg: state.authReducer.authMsg
}
}
function mapDispatchToProps(dispatch){
return{
mySignin(login,password,callback) {
const action = signin(login,password,callback)
dispatch(action)
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Signin)
34
ContentA e B
import React, {Component} from 'react'
import Card from './commons/RestrictCard'
import { connect } from 'react-redux'
import { signout } from '../store/actions/authActionCreator'
class ContentA extends Component{
logout(){
this.props.mySignout(
()=>{
this.props.history.push('/signin')
}
)
}
render(){
return (
<Card title='Conteúdo A' history={this.props.history}>
Conteúdo apenas para usuários. <br /><br />
<button className='btn btn-danger'
onClick={()=>this.logout()}
>
Fazer Logout
</button>
</Card>
)
}
}
Usando o Card restrito.
35
ContentA e B
function mapStateToProps(state) {
return {
userMsg: state.authReducer.authMsg,
firebaseAuth: state.firebaseReducer.auth
}
}
function mapDispatchToProps(dispatch){
return{
mySignout(callback) {
const action = signout(callback)
dispatch(action)
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(ContentA)
36
Referências
●
Código dessa aula foi baseado no projeto de:
– https://github.com/clairechabas/firebase-auth-react-
redux
37
Ajustes na Aplicação de Login
38
Introdução
●
De posse da aplicação passada, iremos fazer
as seguintes alterações:
– Manter estado durante o refresh da página;
– Envio de e-mail para confirmação.
39
Manter o Estado
●
Para manter o estado geral da aplicação,
temos duas soluções:
– Usar uma middleware dedicada (redux-persist)
– Usar o LocalStorage ou SessionStorage
●
Para essa aula, usaremos a abordagem mais
simples, o LocalStorage.
40
storeConfig.js
●
Passaremos as configurações de index.js (raiz)
para um arquivo a parte.
●
Na pasta store crie o arquivo storeConfig.js
(alguns projetos gostam de chamar apenas de
store.js)
41
storeConfig.js
import { createStore, applyMiddleware } from 'redux'
import reduxThunk from 'redux-thunk'
import reducer from '../store/reducers'
import firebase from '../utils/firebase'
const persistedState = loadFromLocalStorage()
const store = createStore(
reducer,
persistedState,
applyMiddleware(reduxThunk)
)
const rrfProps = {
firebase,
config: {},
dispatch: store.dispatch
}
export { store, rrfProps }
42
index.js(raiz)
import { Provider } from 'react-redux'
import { ReactReduxFirebaseProvider} from 'react-redux-firebase'
import { store, rrfProps } from './store/storeConfig'
ReactDOM.render(
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<App />
</ReactReduxFirebaseProvider>
</Provider>
, document.getElementById('root')
);
43
storeConfig.js
●
Voltando ao storeConfig, você deverá adicionar funções
para salvar o estado geral e também carregá-lo.
●
O salvamento do estado geral será feito toda vez que o
mesmo é modificado.
●
O carregamento do estado geral será feito durante a
criação só estado geral (store), através do método
createStore, chamado quando a aplicação é carregada ou
recarregada.
44
storeConfig.js
….
function saveToLocalStorage(state) {
try {
const serializedState = JSON.stringify(state)
localStorage.setItem('state', serializedState)
} catch (error) {
console.log(error)
}
}
function loadFromLocalStorage() {
try {
const serializedState = localStorage.getItem('state')
if (serializedState === null) return undefined
return JSON.parse(serializedState)
} catch (error) {
console.log(error)
return undefined
}
}
const persistedState = loadFromLocalStorage()
const store = createStore(
reducer,
persistedState,
applyMiddleware(reduxThunk)
)
store.subscribe(
() => {
saveToLocalStorage(store.getState())
}
)
...
45
Verificação de E-mail
●
Outra feature interessante do Firebase é que ele permite
a verificação de e-mail.
●
Ele envia um e-mail no momento do signup e, durante o
signin você deve verificar se o usuário verificou o e-
mail.
●
Nas páginas de content você só deixa o usuário acessar
caso ele tenha verificado o e-mail (exercício ded redux).
46
signup
export const signup = (email, password, callback) => {
return dispatch => {
try {
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(
() => {
firebase.auth().onAuthStateChanged(
(user) => {
user.sendEmailVerification();
});
})
.then(
() => {
firebase.auth().onAuthStateChanged(
(user) => {
if (user) {
dispatch({
type: SIGNUP_SUCCESS,
payload: {
authMessage: `Cadastro efetuado com sucesso! Verifque seu e-mail.`,
userMail: '',
verified: false
}
})
callback()
} else {
dispatch({
type: SIGNUP_ERROR,
payload: { authMessage: `Não foi possível conectar` }
})
callback()
}
}
)//firebase.auth().onAuthStateChanged(
}//se deu certo
)
47
signup
.catch(
(error) => {
dispatch({
type: SIGNUP_ERROR,
payload: { authMessage: `Erro na criação do usuário: ${error}` }
})
callback()
}
)
} catch (error) {
dispatch({
type: SIGNUP_ERROR,
payload: { authMessage: `Erro na conexão com o firebase: ${error}` }
})
callback()
} //try-catch
} //return dispatch
}
48
signin
...
.signInWithEmailAndPassword(email, password)
.then(
(data) => {
if(!data.user.emailVerified){
dispatch({
type: EMAIL_NOT_VERIFIED,
payload: {
authMessage: `E-mail não verificado. Veja sua caixa de e-mail.`,
verified: false
}
})
}else{
dispatch({
type: SIGNIN_SUCCESS,
payload: {
authMessage: `Login efetuado com sucesso`,
userMail: data.user.email,
verified: true
}
})
}
callback()
}
)
...
49
authReducer.js
const INITIAL_STATE = {
authMsg: null,
user: '',
verified: false
}
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case SIGNUP_SUCCESS:
return {
...state,
authMsg: action.payload.authMessage,
verified: action.payload.verified
}
case SIGNUP_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
case SIGNIN_SUCCESS:
return {
...state,
authMsg: action.payload.authMessage,
user: action.payload.userMail,
verified: action.payload.verified
}
case SIGNIN_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
case SIGNOUT_SUCCESS:
return {
user: null,
authMsg: action.payload.authMessage,
verified: action.payload.verified
}
case SIGNOUT_ERROR:
return {
...state,
authMsg: action.payload.authMessage
}
case RESET_AUTH_MESSAGE:
return {
...state,
authMsg: null
}
case EMAIL_NOT_VERIFIED:
return {
...state,
authMsg: action.payload.authMessage,
verified: action.payload.verified
}
default:
return state
}
}
50
RestrictedCard.jsx
class RestrictedCard extends Component{
componentDidMount(){
if(this.props.firebaseAuth.isLoaded && this.props.firebaseAuth.isEmpty){
this.props.history.push('/signin')
}
if(!this.props.emailVerified){
this.props.history.push('/signin')
}
}
render(){
return (
<Card title={this.props.title}>
{this.props.children}
</Card>
)
}
}
function mapStateToProps(state) {
return {
firebaseAuth: state.firebaseReducer.auth,
emailVerified: state.authReducer.verified
}
}

Mais conteúdo relacionado

Semelhante a aula09-redux-firebase-auth.pdf

React + Flux (Alt)
React + Flux (Alt)React + Flux (Alt)
React + Flux (Alt)Cezar Luiz
 
Pilares do desenvolvimento Mobile no Nubank
 Pilares do desenvolvimento Mobile no Nubank Pilares do desenvolvimento Mobile no Nubank
Pilares do desenvolvimento Mobile no NubankDevCamp Campinas
 
Javascript (parte 3)
Javascript (parte 3)Javascript (parte 3)
Javascript (parte 3)Alex Camargo
 
Aula 05/06 (Service)
Aula 05/06 (Service)Aula 05/06 (Service)
Aula 05/06 (Service)Ricardo Longa
 
RubyConfBr 2015 - Rails & Javascript: faça isso direito
RubyConfBr 2015 - Rails & Javascript: faça isso direitoRubyConfBr 2015 - Rails & Javascript: faça isso direito
RubyConfBr 2015 - Rails & Javascript: faça isso direitoCezinha Anjos
 
Qualidade de Software: Escrevendo Código Limpo
Qualidade de Software: Escrevendo Código LimpoQualidade de Software: Escrevendo Código Limpo
Qualidade de Software: Escrevendo Código LimpoLidiane Taquehara
 
Introdução ao jquery
Introdução ao jqueryIntrodução ao jquery
Introdução ao jqueryYuri Costa
 
ZF Básico - 6. Autenticação
ZF Básico - 6. AutenticaçãoZF Básico - 6. Autenticação
ZF Básico - 6. AutenticaçãoMarcos Bezerra
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.jsGiovanni Bassi
 
DevDay - O elo perdido: sincronizando webapps
DevDay - O elo perdido: sincronizando webappsDevDay - O elo perdido: sincronizando webapps
DevDay - O elo perdido: sincronizando webappsSuissa
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Androidjoaobmonteiro
 
Windows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows AzureWindows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows AzureVitor Ciaramella
 
Aplicações Web com AJAX - Er Galvão Abbott
Aplicações Web com AJAX - Er Galvão AbbottAplicações Web com AJAX - Er Galvão Abbott
Aplicações Web com AJAX - Er Galvão AbbottTchelinux
 
Minicurso de PHP Com Ajax
Minicurso de PHP Com AjaxMinicurso de PHP Com Ajax
Minicurso de PHP Com AjaxAdler Medrado
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComunidade NetPonto
 

Semelhante a aula09-redux-firebase-auth.pdf (20)

React + Flux (Alt)
React + Flux (Alt)React + Flux (Alt)
React + Flux (Alt)
 
Pilares do desenvolvimento Mobile no Nubank
 Pilares do desenvolvimento Mobile no Nubank Pilares do desenvolvimento Mobile no Nubank
Pilares do desenvolvimento Mobile no Nubank
 
React js
React js React js
React js
 
Javascript (parte 3)
Javascript (parte 3)Javascript (parte 3)
Javascript (parte 3)
 
ASP.NET AJAX
ASP.NET AJAXASP.NET AJAX
ASP.NET AJAX
 
Aula 05/06 (Service)
Aula 05/06 (Service)Aula 05/06 (Service)
Aula 05/06 (Service)
 
RubyConfBr 2015 - Rails & Javascript: faça isso direito
RubyConfBr 2015 - Rails & Javascript: faça isso direitoRubyConfBr 2015 - Rails & Javascript: faça isso direito
RubyConfBr 2015 - Rails & Javascript: faça isso direito
 
Api v3
Api v3Api v3
Api v3
 
Qualidade de Software: Escrevendo Código Limpo
Qualidade de Software: Escrevendo Código LimpoQualidade de Software: Escrevendo Código Limpo
Qualidade de Software: Escrevendo Código Limpo
 
Introdução ao jquery
Introdução ao jqueryIntrodução ao jquery
Introdução ao jquery
 
ZF Básico - 6. Autenticação
ZF Básico - 6. AutenticaçãoZF Básico - 6. Autenticação
ZF Básico - 6. Autenticação
 
Wicket 2008
Wicket 2008Wicket 2008
Wicket 2008
 
Python 08
Python 08Python 08
Python 08
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.js
 
DevDay - O elo perdido: sincronizando webapps
DevDay - O elo perdido: sincronizando webappsDevDay - O elo perdido: sincronizando webapps
DevDay - O elo perdido: sincronizando webapps
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Android
 
Windows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows AzureWindows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows Azure
 
Aplicações Web com AJAX - Er Galvão Abbott
Aplicações Web com AJAX - Er Galvão AbbottAplicações Web com AJAX - Er Galvão Abbott
Aplicações Web com AJAX - Er Galvão Abbott
 
Minicurso de PHP Com Ajax
Minicurso de PHP Com AjaxMinicurso de PHP Com Ajax
Minicurso de PHP Com Ajax
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noite
 

Último

Mapa mental - Classificação dos seres vivos .docx
Mapa mental - Classificação dos seres vivos .docxMapa mental - Classificação dos seres vivos .docx
Mapa mental - Classificação dos seres vivos .docxBeatrizLittig1
 
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...licinioBorges
 
Música Meu Abrigo - Texto e atividade
Música   Meu   Abrigo  -   Texto e atividadeMúsica   Meu   Abrigo  -   Texto e atividade
Música Meu Abrigo - Texto e atividadeMary Alvarenga
 
Literatura Brasileira - escolas literárias.ppt
Literatura Brasileira - escolas literárias.pptLiteratura Brasileira - escolas literárias.ppt
Literatura Brasileira - escolas literárias.pptMaiteFerreira4
 
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdf
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdfPROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdf
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdfMarianaMoraesMathias
 
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptx
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptxAULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptx
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptxLaurindo6
 
A poesia - Definições e Característicass
A poesia - Definições e CaracterísticassA poesia - Definições e Característicass
A poesia - Definições e CaracterísticassAugusto Costa
 
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃO
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃOLEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃO
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃOColégio Santa Teresinha
 
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicas
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicasCenários de Aprendizagem - Estratégia para implementação de práticas pedagógicas
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicasRosalina Simão Nunes
 
Gerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalGerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalJacqueline Cerqueira
 
interfaces entre psicologia e neurologia.pdf
interfaces entre psicologia e neurologia.pdfinterfaces entre psicologia e neurologia.pdf
interfaces entre psicologia e neurologia.pdfIvoneSantos45
 
Noções de Farmacologia - Flávia Soares.pdf
Noções de Farmacologia - Flávia Soares.pdfNoções de Farmacologia - Flávia Soares.pdf
Noções de Farmacologia - Flávia Soares.pdflucassilva721057
 
Livro O QUE É LUGAR DE FALA - Autora Djamila Ribeiro
Livro O QUE É LUGAR DE FALA  - Autora Djamila RibeiroLivro O QUE É LUGAR DE FALA  - Autora Djamila Ribeiro
Livro O QUE É LUGAR DE FALA - Autora Djamila RibeiroMarcele Ravasio
 
RedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfRedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfAlissonMiranda22
 
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptx
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptxSlides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptx
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptxLuizHenriquedeAlmeid6
 
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptx
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptxSlides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptx
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptxLuizHenriquedeAlmeid6
 
Transformações isométricas.pptx Geometria
Transformações isométricas.pptx GeometriaTransformações isométricas.pptx Geometria
Transformações isométricas.pptx Geometriajucelio7
 
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumGÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumAugusto Costa
 
E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?Rosalina Simão Nunes
 
Pedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxPedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxleandropereira983288
 

Último (20)

Mapa mental - Classificação dos seres vivos .docx
Mapa mental - Classificação dos seres vivos .docxMapa mental - Classificação dos seres vivos .docx
Mapa mental - Classificação dos seres vivos .docx
 
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...
11oC_-_Mural_de_Portugues_4m35.pptxTrabalho do Ensino Profissional turma do 1...
 
Música Meu Abrigo - Texto e atividade
Música   Meu   Abrigo  -   Texto e atividadeMúsica   Meu   Abrigo  -   Texto e atividade
Música Meu Abrigo - Texto e atividade
 
Literatura Brasileira - escolas literárias.ppt
Literatura Brasileira - escolas literárias.pptLiteratura Brasileira - escolas literárias.ppt
Literatura Brasileira - escolas literárias.ppt
 
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdf
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdfPROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdf
PROGRAMA DE AÇÃO 2024 - MARIANA DA SILVA MORAES.pdf
 
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptx
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptxAULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptx
AULA SOBRE AMERICA LATINA E ANGLO SAXONICA.pptx
 
A poesia - Definições e Característicass
A poesia - Definições e CaracterísticassA poesia - Definições e Característicass
A poesia - Definições e Característicass
 
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃO
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃOLEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃO
LEMBRANDO A MORTE E CELEBRANDO A RESSUREIÇÃO
 
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicas
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicasCenários de Aprendizagem - Estratégia para implementação de práticas pedagógicas
Cenários de Aprendizagem - Estratégia para implementação de práticas pedagógicas
 
Gerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalGerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem Organizacional
 
interfaces entre psicologia e neurologia.pdf
interfaces entre psicologia e neurologia.pdfinterfaces entre psicologia e neurologia.pdf
interfaces entre psicologia e neurologia.pdf
 
Noções de Farmacologia - Flávia Soares.pdf
Noções de Farmacologia - Flávia Soares.pdfNoções de Farmacologia - Flávia Soares.pdf
Noções de Farmacologia - Flávia Soares.pdf
 
Livro O QUE É LUGAR DE FALA - Autora Djamila Ribeiro
Livro O QUE É LUGAR DE FALA  - Autora Djamila RibeiroLivro O QUE É LUGAR DE FALA  - Autora Djamila Ribeiro
Livro O QUE É LUGAR DE FALA - Autora Djamila Ribeiro
 
RedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfRedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdf
 
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptx
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptxSlides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptx
Slides Lição 04, Central Gospel, O Tribunal De Cristo, 1Tr24.pptx
 
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptx
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptxSlides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptx
Slides Lição 03, Central Gospel, O Arrebatamento, 1Tr24.pptx
 
Transformações isométricas.pptx Geometria
Transformações isométricas.pptx GeometriaTransformações isométricas.pptx Geometria
Transformações isométricas.pptx Geometria
 
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumGÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
 
E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?
 
Pedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxPedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptx
 

aula09-redux-firebase-auth.pdf

  • 1. 1 Desenvolvimento de Software para WEB Redux-Firebase-Authentication
  • 2. 2 Introdução ● Neste projeto, iremos implementar uma aplicação de cadastro (signup), login (signin) e logout, fazendo uso do firebase authentication para gerenciar usuários e senhas. ● O seu projeto irá necessitar das seguintes bibliotecas: – "firebase": "^7.14.4" → Acesso à API do Firebase. É necessário ter conta no Google – "redux": "^4.0.5" → Redux “puro” – "react-redux": "^7.2.0" → “Cola” entre o React e o Redux – "react-redux-firebase": "^3.5.1" → “Cola” entre o React, Redux e Firebase – "react-router-dom": "^5.1.2" → Gerenciador de rotas – "redux-thunk": "^2.3.0" → Middleware reponsável por ações assíncronas
  • 3. 3 Firebase Authentication ● Crie um projeto no Firebase e vá em Authentication:
  • 4. 4 Firebase Authentication ● Na forma de login, escolha por e-mail/senha
  • 5. 5 Firebase Authentication ● Em configurações do projeto, crie uma aplicação WEB para acessar o projeto e copie a chave de autenticação a ser colocada no arquivo javascript do seu projeto.
  • 6. 6 O Projeto React ● Uma vez instaladas as bibliotecas, crie o seguinte esquema de pastas:
  • 7. 7 Conexão com o Firebase ● Na pasta keys, crie o arquivo firebase_key.js: const firebase_key = { apiKey: "SDdsddkse8dsd-WlGeik_sdsdsdeeEEEsssddsd", authDomain: "pet-redux-auth.firebaseapp.com", databaseURL: "https://pet-dsdsdsds-dsd.dsdddd.com", projectId: "pet-sdsddsd-authksdsdeeedusyd", StorageBucket: "????", messagingSenderId: "0000000000", appId: "1sldjslue!!!sdssdsdsd:webskdhksds23033fa13315219d685e7a" } export default firebase_key
  • 8. 8 Conexão com Firebase ● Na pasta utils, crie o arquivo firebase.js import firebase from 'firebase/app' import 'firebase/auth' import firebase_key from '../keys/firebase_key' firebase.initializeApp(firebase_key) export default firebase
  • 9. 9 Conexão com Firebase ● Note que o arquivo firebase.js usa o arquivo firebase_key.js, para poder fazer a conexão com o Firebase. ● Você deve ter criado um projeto no Firebase e um aplicação WEB, gerando assim a chave de conexão.
  • 10. 10 Reducers ● Os reducers, armazenam o estado geral da aplicação de uma determinada entidade do domínio da aplicação. No nosso caso, iremos armazenar a mensagem gerada pelas operações de cadastro, login e logout. ● Cada reducer é um função que recebe como parâmetro um state (estado geral anterior) e uma action (ação). ● Na pasta reducers iremos criar: – authReducer.js (redutor reponsável pela autiorização) – Index.js (estado geral da aplicação, a combinação de todos os redutores)
  • 11. 11 authReducer.js import { SIGNUP_SUCCESS, SIGNUP_ERROR, SIGNIN_SUCCESS, SIGNIN_ERROR, SIGNOUT_SUCCESS, SIGNOUT_ERROR } from '../actions/actionTypes' const INITIAL_STATE = { authMsg: null, user: '' } export default function (state = INITIAL_STATE, action) { console.log('action: ' + action.type + ' ' + state.user) switch (action.type) { case SIGNUP_SUCCESS: return { ...state, authMsg: action.payload.authMessage, user: action.payload.userMail, } case SIGNUP_ERROR: return { ...state, authMsg: action.payload.authMessage } case SIGNIN_SUCCESS: return { ...state, authMsg: action.payload.authMessage, user: action.payload.userMail, } case SIGNIN_ERROR: return { ...state, authMsg: action.payload.authMessage } case SIGNOUT_SUCCESS: return { user: null, authMsg: action.payload.authMessage } case SIGNOUT_ERROR: return { ...state, authMsg: action.payload.authMessage } default: return state } } Atenção! O arquivo actionTypes.js deve ser Criado antes. Atenção! Cada “case” trata de um tipo de action diferente. Lembre-se: toda vez que o usuário Der um refresh na página (F5), o estado é resetado para o inicial. Para este exemplo, iremos armazenar apenas a mensagem de resultado de uma ação “authMsg” e “user”, o qual armazera o e-mail logado.
  • 12. 12 index.js import {combineReducers} from 'redux' import authReducer from './authReducer' import { firebaseReducer } from 'react-redux-firebase' /* ESTADO GERAL DA APLICAÇÃO */ export default combineReducers({ firebaseReducer, authReducer }) Temos dois redutores (reducers) declarados neste arquivo: “firebaseReducer”, definido pela biblioteca react-redux-firebase; e “authReducer”, criado por nós para guardar informações do usário logado.
  • 13. 13 Actions ● As ações são disparadas de acordo com eventos da interface do usuário (navegador). ● As ações podem alterar o estado geral da aplicação (definido em reducers/index.js), acionando os redutores (que escolhem qual ação irão computar). ● Cada ação tem um tipo (type) e um payload (informações do novo estado). ● No nosso projeto, dentro da pastas actions, temos: – actionTypes.js (arquivo simples de constantes) – authActionCreator.js (criador de ações) ● Na verdade, as ações são objetos simples em javascript ( {type,payload}). O arquivo authActionCreator é formado por três funções (action creators) responsáveis em retornar uma ação. São elas: – signin (email,passwor,callback) → A função de login – signup (email,passwor,callback) → A função de cadastro – signout () → A função de logout
  • 14. 14 actionType.js export const SIGNUP_SUCCESS = 'SIGNUP_SUCCESS' export const SIGNUP_ERROR = 'SIGNUP_ERROR' export const SIGNIN_SUCCESS = 'SIGNIN_SUCCESS' export const SIGNIN_ERROR = 'SIGNIN_ERROR' export const SIGNOUT_SUCCESS = 'SIGNOUT_SUCCESS' export const SIGNOUT_ERROR = 'SIGNOUT_ERROR' Define um conjunto de constantes que facilita e padroniza o uso das ações, evitando erros de grafia.
  • 15. 15 authActionCreator.js signup import {SIGNUP_SUCCESS,SIGNUP_ERROR,SIGNIN_SUCCESS,SIGNIN_ERROR,SIGNOUT_SUCCESS,SIGNOUT_ERROR} from './actionTypes' import firebase from '../../utils/firebase' export const signup = (email,password,callback) => { return dispatch =>{ try{ firebase .auth() .createUserWithEmailAndPassword(email,password) .then( ()=>{ firebase.auth().onAuthStateChanged( (user)=>{ if(user){ dispatch({ type:SIGNUP_SUCCESS, payload: { authMessage: `Cadastro efetuado com sucesso!`, userMail: user.email} }) callback() }else{ dispatch({ type:SIGNUP_ERROR, payload: {authMessage: `Não foi possível conectar`} }) callback() } } )//firebase.auth().onAuthStateChanged( }//se deu certo ) Atenção! Diferente do Redux usual, as nossas funções não retornam apenas um objeto referente a ação, e sim uma função: dispatch=>{ } . Isso se deve graças a Middleware redux-thunk, pois no caso de signin, signout e signup temos operações assíncronas. Para tratar operações assíncronas, o redux-thunk envolve as ações {type, payload} dentro da função dispatch=>{}, possibilitando assim que sua aplicação não “trave” ao fazer uma chamada remota ao Firebase.
  • 16. 16 authActionCreator.js signup .catch( (error)=>{ dispatch({ type: SIGNUP_ERROR, payload: {authMessage:`Erro na criação do usuário: ${error}`} }) callback() } ) }catch(error){ dispatch({ type: SIGNUP_ERROR, payload: { authMessage: `Erro na conexão com o firebase: ${error}`} }) callback() } //try-catch } //return dispatch } A função callback(), passada como parâmetro, possibilita aos componentes que chamarem essas ações “esperarem” dentro do callback a computação remota acabar. Isto pode ser interessante em casos que a interface remota queira renderizar uma tela de loading, que só fecha quando o resultado remoto é obtido. Veremos mais detalhes do uso do callback no signin e signup, na interface.
  • 17. 17 authActionCreator.js signin export const signin = (email,password,callback) =>{ return dispatch => { try{ firebase .auth() .signInWithEmailAndPassword(email,password) .then( (data)=>{ dispatch({ type: SIGNIN_SUCCESS, payload: { authMessage:`Login efetuado com sucesso`, userMail: data.user.email} }) callback() } ) .catch( (error)=>{ dispatch({ type: SIGNIN_ERROR, payload: {authMessage:`Erro login do usuário: ${error}`} }) callback() } ) A lógica do Signin não é muito diferente de Signout.
  • 18. 18 authActionCreator.js signin }catch(error){ dispatch({ type: SIGNIN_ERROR, payload: { authMessage: `Erro na conexão com o firebase: ${error}`} }) callback() } } }
  • 19. 19 authActionCreator.js signout export const signout = (callback) => { return dispatch => { try{ firebase .auth() .signOut() .then( ()=>{ dispatch({ type: SIGNOUT_SUCCESS, payload: {authMessage:`Signout efetuado com sucesso`} }) callback() } ) .catch( (error)=>{ dispatch({ type: SIGNOUT_ERROR, payload: {authMessage:`Erro logout: ${error}`} }) callback() } )
  • 20. 20 authActionCreator.js signout }catch(error){ dispatch({ type: SIGNOUT_ERROR, payload: { authMessage: `Erro na conexão com o firebase: ${error}`} }) callback() } } }
  • 21. 21 Componentes Auxiliares ● Dentro da pasta commons, iremos criar dois componentes de interface auxiliares: – Card.jsx → Acesso irrestrito – RestrictedCard.jsx → Acessível apenas com o usuário logado
  • 22. 22 Card.jsx import React, { Component } from 'react' export default class Card extends Component { render() { return ( <div className='content'> <div className='card'> <div className='card-header'> {this.props.title} </div> <div className='card-body'> {this.props.children} </div> </div> </div> ) } } Usa os “cards” do bootstrap. Mais detalhes em https://getbootstrap.com/docs/4.3/components/card/
  • 23. 23 RestrictedCard.jsx import React, {Component} from 'react' import Card from './Card' import { connect } from 'react-redux' class RestrictedCard extends Component{ componentDidMount(){ if(this.props.firebaseAuth.isLoaded && this.props.firebaseAuth.isEmpty){ this.props.history.push('/signin') } } render(){ return ( <Card title={this.props.title}> {this.props.children} </Card> ) } } function mapStateToProps(state) { return { firebaseAuth: state.firebaseReducer.auth } } export default connect(mapStateToProps)(RestrictedCard) Agora, fazendo uso do redutor do firebase, definido em reducers/index.js, eu Testo se o usuário ainda está logado.
  • 24. 24 Colando o Redux ● Para inserir o Redux, temos que criar os objetos no arquivo principal da aplicação, o index.js de src. ● Você deve seguir o que diz a documentação: – http://react-redux-firebase.com/docs/v3-migration-g uide.html
  • 25. 25 index.js import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import 'bootstrap/dist/css/bootstrap.min.css' import App from './App'; import * as serviceWorker from './serviceWorker'; import { createStore, applyMiddleware } from 'redux' import { Provider } from 'react-redux' import { ReactReduxFirebaseProvider} from 'react-redux-firebase' import reduxThunk from 'redux-thunk' import reducer from './store/reducers' //chamando index.js import firebase from './utils/firebase' const store = createStore( reducer, {}, applyMiddleware(reduxThunk) ) const rrfProps = { firebase, config: {}, dispatch: store.dispatch } ReactDOM.render( <Provider store={store}> <ReactReduxFirebaseProvider {...rrfProps}> <App /> </ReactReduxFirebaseProvider> </Provider> , document.getElementById('root') ); serviceWorker.unregister(); Cria o estado geral e aplica a middleware, que trata de comunição assíncrona. Configurações gerais do Firebase, usadas pelo “react-redux-firebase”
  • 26. 26 Componentes da Aplicação ● Os componentes da aplicação são: – Main.jsx → Apenas pra encher linguiça, escreva qualquer coisa. – Signinjsx → Login – Signup.jsx → Cadastro – Content A e B .jsx →páginas de acesso restrito – App.jsx → Página raiz
  • 27. 27 App.jsx import React, { Component } from 'react' import { BrowserRouter, Link, Switch, Route } from 'react-router-dom' import Main from './components/Main' import Signin from './components/Signin' import Signup from './components/Signup' import ContentA from './components/ContentA' import ContentB from './components/ContentB' import { connect } from 'react-redux' class App extends Component { render() { return ( <BrowserRouter> <div className='container'> <nav className='navbar navbar-expand-lg navbar-light bg-light'> <Link to={'/'} className='navbar-brand'>PET Firebase Auth</Link> <div className='collapse navbar-collapse' id='navbarSupportedContent'> <ul className='navbar-nav mr-auto'> <li> <Link to={'/'} className='nav-link'>Home</Link> </li> <li> <Link to={'/signin'} className='nav-link'>Login</Link> </li> <li> <Link to={'/signup'} className='nav-link'>Cadastrar</Link> </li> <li> <Link to={'/contentA'} className='nav-link'>Conteúdo A</Link> </li> <li> <Link to={'/contentB'} className='nav-link'>Conteúdo B</Link> </li> </ul> {this.props.user} </div> </nav> <Switch> <Route exact path='/' component={Main}/> <Route path='/signin' component={Signin}/> <Route path='/signup' component={Signup}/> <Route path='/contentA' component={ContentA}/> <Route path='/contentB' component={ContentB}/> </Switch> </div> </BrowserRouter> ) } } function mapStateToProps(state){ return{ user: state.authReducer.user } } export default connect(mapStateToProps)(App) Importando os componentes. Imprimindo o valor da variável do estado geral, “user”.
  • 28. 28 Signup.jsx (Cadastrar) import React, { Component } from 'react' import Card from './commons/Card' import { connect } from 'react-redux' import { signup } from '../store/actions/authActionCreator' class Signup extends Component { constructor(props) { super(props) this.state = { login: '', password: '' } this.setLogin = this.setLogin.bind(this) this.setPassword = this.setPassword.bind(this) this.onSubmit = this.onSubmit.bind(this) this._isMounted = false } componentDidMount(){ this._isMounted = true } componentWillUnmount(){ this._isMounted = false } setLogin(e) { this.setState({ login: e.target.value }) } setPassword(e) { this.setState({ password: e.target.value }) }
  • 29. 29 Signup.jsx (Cadastrar) onSubmit(e) { e.preventDefault() this.setState({loading:true}) this.props.mySignup(this.state.login, this.state.password, ()=>{ this._isMounted && this.setState({loading:false}) }) this.setState({ login: '', password: ''}) } renderButton() { if (this.state.loading) { return ( <button className="btn btn-primary" type="button" disabled> <span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Carregando... </button> ) } return ( <input type='submit' value='Cadastrar' className='btn btn-primary' /> ) } renderMessage() { if (this.props.userMsg) { const msgType = (this.props.userMsg.includes('Err') ? 'alert-danger' : 'alert-info') return ( <div className={`alert ${msgType}`} style={{ marginTop: '10px' }}> {this.props.userMsg} </div> ) } return } A implementação da função callback só será chamada quando a operação remota terminar.
  • 30. 30 Signup.jsx (Cadastrar) render() { return ( <Card title='Cadastrar'> <form onSubmit={this.onSubmit}> <div className='form-group'> <label>Login: </label> <input type='text' className='form-control' value={this.state.login} onChange={this.setLogin} /> </div> <div className='form-group'> <label>Password: </label> <input type='password' className='form-control' value={this.state.password} onChange={this.setPassword} /> </div> {this.renderButton()} </form> {this.renderMessage()} </Card> ) } } function mapStateToProps(state) { return { userMsg: state.authReducer.authMsg } } function mapDispatchToProps(dispatch) { return { mySignup(login, password,callback) { const action = signup(login, password,callback) dispatch(action) } } } export default connect(mapStateToProps, mapDispatchToProps)(Signup)
  • 31. 31 Signin.jsx (Fazer login) import React, {Component} from 'react' import Card from './commons/Card' import { connect } from 'react-redux' import { signin } from '../store/actions/authActionCreator' class Signin extends Component{ constructor(props){ super(props) this.state = {login:'',password:'',loading:false} this.setLogin = this.setLogin.bind(this) this.setPassword = this.setPassword.bind(this) this.onSubmit = this.onSubmit.bind(this) } setLogin(e){ this.setState({login:e.target.value}) } setPassword(e){ this.setState({password:e.target.value}) } renderButton() { if (this.state.loading) { return ( <button className="btn btn-primary" type="button" disabled> <span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Carregando... </button> ) } return ( <input type='submit' value='Efetuar Login' className='btn btn-primary' /> ) }
  • 32. 32 Signin.jsx (Fazer login) renderMessage() { if (this.props.userMsg) { const msgType = (this.props.userMsg.includes('Err') ? 'alert-danger' : 'alert-info') return ( <div className={`alert ${msgType}`} style={{ marginTop: '10px' }}> {this.props.userMsg} </div> ) } return } onSubmit(e){ e.preventDefault() this.setState({loading:true}) this.props.mySignin(this.state.login,this.state.password, ()=>{ this.setState({loading:false}) }) this.setState({login:'',password:''}) }
  • 33. 33 Signin.jsx (Fazer login) render(){ return ( <Card title='Fazer Login'> <form onSubmit={this.onSubmit}> <div className='form-group'> <label>Login: </label> <input type='text' className='form-control' value={this.state.login} onChange={this.setLogin} /> </div> <div className='form-group'> <label>Password: </label> <input type='password' className='form-control' value={this.state.password} onChange={this.setPassword} /> </div> {this.renderButton()} </form> {this.renderMessage()} </Card> ) } } function mapStateToProps(state) { return { userMsg: state.authReducer.authMsg } } function mapDispatchToProps(dispatch){ return{ mySignin(login,password,callback) { const action = signin(login,password,callback) dispatch(action) } } } export default connect(mapStateToProps,mapDispatchToProps)(Signin)
  • 34. 34 ContentA e B import React, {Component} from 'react' import Card from './commons/RestrictCard' import { connect } from 'react-redux' import { signout } from '../store/actions/authActionCreator' class ContentA extends Component{ logout(){ this.props.mySignout( ()=>{ this.props.history.push('/signin') } ) } render(){ return ( <Card title='Conteúdo A' history={this.props.history}> Conteúdo apenas para usuários. <br /><br /> <button className='btn btn-danger' onClick={()=>this.logout()} > Fazer Logout </button> </Card> ) } } Usando o Card restrito.
  • 35. 35 ContentA e B function mapStateToProps(state) { return { userMsg: state.authReducer.authMsg, firebaseAuth: state.firebaseReducer.auth } } function mapDispatchToProps(dispatch){ return{ mySignout(callback) { const action = signout(callback) dispatch(action) } } } export default connect(mapStateToProps,mapDispatchToProps)(ContentA)
  • 36. 36 Referências ● Código dessa aula foi baseado no projeto de: – https://github.com/clairechabas/firebase-auth-react- redux
  • 38. 38 Introdução ● De posse da aplicação passada, iremos fazer as seguintes alterações: – Manter estado durante o refresh da página; – Envio de e-mail para confirmação.
  • 39. 39 Manter o Estado ● Para manter o estado geral da aplicação, temos duas soluções: – Usar uma middleware dedicada (redux-persist) – Usar o LocalStorage ou SessionStorage ● Para essa aula, usaremos a abordagem mais simples, o LocalStorage.
  • 40. 40 storeConfig.js ● Passaremos as configurações de index.js (raiz) para um arquivo a parte. ● Na pasta store crie o arquivo storeConfig.js (alguns projetos gostam de chamar apenas de store.js)
  • 41. 41 storeConfig.js import { createStore, applyMiddleware } from 'redux' import reduxThunk from 'redux-thunk' import reducer from '../store/reducers' import firebase from '../utils/firebase' const persistedState = loadFromLocalStorage() const store = createStore( reducer, persistedState, applyMiddleware(reduxThunk) ) const rrfProps = { firebase, config: {}, dispatch: store.dispatch } export { store, rrfProps }
  • 42. 42 index.js(raiz) import { Provider } from 'react-redux' import { ReactReduxFirebaseProvider} from 'react-redux-firebase' import { store, rrfProps } from './store/storeConfig' ReactDOM.render( <Provider store={store}> <ReactReduxFirebaseProvider {...rrfProps}> <App /> </ReactReduxFirebaseProvider> </Provider> , document.getElementById('root') );
  • 43. 43 storeConfig.js ● Voltando ao storeConfig, você deverá adicionar funções para salvar o estado geral e também carregá-lo. ● O salvamento do estado geral será feito toda vez que o mesmo é modificado. ● O carregamento do estado geral será feito durante a criação só estado geral (store), através do método createStore, chamado quando a aplicação é carregada ou recarregada.
  • 44. 44 storeConfig.js …. function saveToLocalStorage(state) { try { const serializedState = JSON.stringify(state) localStorage.setItem('state', serializedState) } catch (error) { console.log(error) } } function loadFromLocalStorage() { try { const serializedState = localStorage.getItem('state') if (serializedState === null) return undefined return JSON.parse(serializedState) } catch (error) { console.log(error) return undefined } } const persistedState = loadFromLocalStorage() const store = createStore( reducer, persistedState, applyMiddleware(reduxThunk) ) store.subscribe( () => { saveToLocalStorage(store.getState()) } ) ...
  • 45. 45 Verificação de E-mail ● Outra feature interessante do Firebase é que ele permite a verificação de e-mail. ● Ele envia um e-mail no momento do signup e, durante o signin você deve verificar se o usuário verificou o e- mail. ● Nas páginas de content você só deixa o usuário acessar caso ele tenha verificado o e-mail (exercício ded redux).
  • 46. 46 signup export const signup = (email, password, callback) => { return dispatch => { try { firebase .auth() .createUserWithEmailAndPassword(email, password) .then( () => { firebase.auth().onAuthStateChanged( (user) => { user.sendEmailVerification(); }); }) .then( () => { firebase.auth().onAuthStateChanged( (user) => { if (user) { dispatch({ type: SIGNUP_SUCCESS, payload: { authMessage: `Cadastro efetuado com sucesso! Verifque seu e-mail.`, userMail: '', verified: false } }) callback() } else { dispatch({ type: SIGNUP_ERROR, payload: { authMessage: `Não foi possível conectar` } }) callback() } } )//firebase.auth().onAuthStateChanged( }//se deu certo )
  • 47. 47 signup .catch( (error) => { dispatch({ type: SIGNUP_ERROR, payload: { authMessage: `Erro na criação do usuário: ${error}` } }) callback() } ) } catch (error) { dispatch({ type: SIGNUP_ERROR, payload: { authMessage: `Erro na conexão com o firebase: ${error}` } }) callback() } //try-catch } //return dispatch }
  • 48. 48 signin ... .signInWithEmailAndPassword(email, password) .then( (data) => { if(!data.user.emailVerified){ dispatch({ type: EMAIL_NOT_VERIFIED, payload: { authMessage: `E-mail não verificado. Veja sua caixa de e-mail.`, verified: false } }) }else{ dispatch({ type: SIGNIN_SUCCESS, payload: { authMessage: `Login efetuado com sucesso`, userMail: data.user.email, verified: true } }) } callback() } ) ...
  • 49. 49 authReducer.js const INITIAL_STATE = { authMsg: null, user: '', verified: false } export default function (state = INITIAL_STATE, action) { switch (action.type) { case SIGNUP_SUCCESS: return { ...state, authMsg: action.payload.authMessage, verified: action.payload.verified } case SIGNUP_ERROR: return { ...state, authMsg: action.payload.authMessage } case SIGNIN_SUCCESS: return { ...state, authMsg: action.payload.authMessage, user: action.payload.userMail, verified: action.payload.verified } case SIGNIN_ERROR: return { ...state, authMsg: action.payload.authMessage } case SIGNOUT_SUCCESS: return { user: null, authMsg: action.payload.authMessage, verified: action.payload.verified } case SIGNOUT_ERROR: return { ...state, authMsg: action.payload.authMessage } case RESET_AUTH_MESSAGE: return { ...state, authMsg: null } case EMAIL_NOT_VERIFIED: return { ...state, authMsg: action.payload.authMessage, verified: action.payload.verified } default: return state } }
  • 50. 50 RestrictedCard.jsx class RestrictedCard extends Component{ componentDidMount(){ if(this.props.firebaseAuth.isLoaded && this.props.firebaseAuth.isEmpty){ this.props.history.push('/signin') } if(!this.props.emailVerified){ this.props.history.push('/signin') } } render(){ return ( <Card title={this.props.title}> {this.props.children} </Card> ) } } function mapStateToProps(state) { return { firebaseAuth: state.firebaseReducer.auth, emailVerified: state.authReducer.verified } }