Terakhir diperbarui: 2021-05-03
Penulis: Habibie Ed Dien, S.Kom., M.T.
Pada codelab ini Anda akan mempelajari tentang penggunaan Redux-Thunk dan penerapannya dengan Firebase Login di ReactJS.
Sebelum memulai codelab ini, sebaiknya Anda memiliki pengetahuan dasar tentang:
Istilah "thunk" merupakan humoris atau candaan kata past tense dari "think". Sebenarnya Redux Thunk adalah middleware yang memungkinkan Anda memanggil pembuat aksi yang mengembalikan fungsi sebagai ganti objek aksi. Fungsi itu menerima metode pengiriman penyimpanan, yang kemudian digunakan untuk mengirim aksi sinkron di dalam isi fungsi setelah operasi asinkron selesai.
Kita mengetahui bahwa Redux mengembalikan dalam bentuk props actions yang didefinisikan oleh Reducers, namun masalahnya jika kita ingin mengembalikan sebuah function, Redux tidak dapat menanganinya. Oleh karena itu, kita membutuhkan middleware yang berfungsi untuk mengembalikan action. Jadi, Redux Thunk adalah sebuah middleware yang memungkinkan untuk menulis Action yang mengembalikan function, bukan action.
Sebuah "thunk" adalah sebuah fungsi yang membungkus suatu ekspresi untuk dilakukan evaluasi nanti. Perhatikan contoh kode JavaScript berikut ini.
// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;
// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;
Untuk menggunakan library ini, perlu kita install terlebih dahulu di project React kita. Caranya lakukan perintah berikut pada terminal atau console.
npm install --save redux-thunk
Kemudian untuk mengaktifkan Redux Thunk, gunakan fungsi applyMiddleware()
:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Pada praktikum ini, kita dapat melanjutkan dari codelab sebelumnya (Codelab 10 - Firebase di ReactJS). Praktikum ini akan membuat form login yang dapat mengarahkan ke halaman yang dilindungi dengan password. Jadi, halaman tersebut tidak akan bisa diakses kecuali user telah melakukan login. Untuk membuatnya, silakan lakukan langkah-langkah praktikum berikut ini.
firebase.config.js
seperti berikut.import firebase from "firebase/app";
import "firebase/auth";
export const firebaseConfig = {
apiKey: "isikan sesuai value dari console firebase Anda",
authDomain: "isikan sesuai value dari console firebase Anda",
projectId: "isikan sesuai value dari console firebase Anda",
storageBucket: "isikan sesuai value dari console firebase Anda",
messagingSenderId: "isikan sesuai value dari console firebase Anda",
appId: "isikan sesuai value dari console firebase Anda",
measurementId: "isikan sesuai value dari console firebase Anda"
};
export const myFirebase = firebase.initializeApp(firebaseConfig);
src/
redux/actions/auth.js
lalu isi dengan kode berikut.import { myFirebase } from "../../firebase.config";
export const LOGIN_REQUEST = "LOGIN_REQUEST";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAILURE = "LOGIN_FAILURE";
export const LOGOUT_REQUEST = "LOGOUT_REQUEST";
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
export const LOGOUT_FAILURE = "LOGOUT_FAILURE";
export const VERIFY_REQUEST = "VERIFY_REQUEST";
export const VERIFY_SUCCESS = "VERIFY_SUCCESS";
const requestLogin = () => {
return {
type: LOGIN_REQUEST
};
};
const receiveLogin = user => {
return {
type: LOGIN_SUCCESS,
user
};
};
const loginError = () => {
return {
type: LOGIN_FAILURE
};
};
const requestLogout = () => {
return {
type: LOGOUT_REQUEST
};
};
const receiveLogout = () => {
return {
type: LOGOUT_SUCCESS
};
};
const logoutError = () => {
return {
type: LOGOUT_FAILURE
};
};
const verifyRequest = () => {
return {
type: VERIFY_REQUEST
};
};
const verifySuccess = () => {
return {
type: VERIFY_SUCCESS
};
};
export const loginUser = (email, password) => dispatch => {
dispatch(requestLogin());
myFirebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(user => {
dispatch(receiveLogin(user));
})
.catch(error => {
//Do something with the error if you want!
dispatch(loginError());
});
}
export const logoutUser = () => dispatch => {
dispatch(requestLogout());
myFirebase
.auth()
.signOut()
.then(() => {
dispatch(receiveLogout());
})
.catch(error => {
//Do something with the error if you want!
dispatch(logoutError());
});
};
export const verifyAuth = () => dispatch => {
dispatch(verifyRequest());
myFirebase.auth().onAuthStateChanged(user => {
if (user !== null) {
dispatch(receiveLogin(user));
}
dispatch(verifySuccess());
});
};
src/redux/
reducers/auth.js
.import {
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILURE,
LOGOUT_REQUEST,
LOGOUT_SUCCESS,
LOGOUT_FAILURE,
VERIFY_REQUEST,
VERIFY_SUCCESS
} from "../actions/auth";
export default (
state = {
isLoggingIn: false,
isLoggingOut: false,
isVerifying: false,
loginError: false,
logoutError: false,
isAuthenticated: false,
user: {}
},
action
) => {
switch (action.type) {
case LOGIN_REQUEST:
return {
...state,
isLoggingIn: true,
loginError: false
};
case LOGIN_SUCCESS:
return {
...state,
isLoggingIn: false,
isAuthenticated: true,
user: action.user
};
case LOGIN_FAILURE:
return {
...state,
isLoggingIn: false,
isAuthenticated: false,
loginError: true
};
case LOGOUT_REQUEST:
return {
...state,
isLoggingOut: true,
logoutError: false
};
case LOGOUT_SUCCESS:
return {
...state,
isLoggingOut: false,
isAuthenticated: false,
user: {}
};
case LOGOUT_FAILURE:
return {
...state,
isLoggingOut: false,
logoutError: true
};
case VERIFY_REQUEST:
return {
...state,
isVerifying: true,
verifyingError: false
};
case VERIFY_SUCCESS:
return {
...state,
isVerifying: false
};
default:
return state;
}
};
index.js
di folder reducers
tersebut yang isinya seperti berikut.import { combineReducers } from "redux";
import auth from "./auth";
export default combineReducers({ auth });
src/redux/
configureStore.js
untuk mengonfigurasi store kita dengan Redux Thunk. Jangan lupa library Redux Thunk diinstall seperti pada langkah materi sebelumnya pada codelab ini. Isi kode dari file configureStore.js
adalah sebagai berikut.import { applyMiddleware, createStore } from "redux";
import thunkMiddleware from "redux-thunk";
import { verifyAuth } from "./actions/auth";
import rootReducer from "./reducers";
export default function configureStore (persistedState) {
const store = createStore(
rootReducer,
persistedState,
applyMiddleware(thunkMiddleware)
);
store.dispatch(verifyAuth());
return store;
}
Login
atau dapat menggunakan komponen Login dari Codelab 10. Buka file Login.js
di src/components
. Sesuaikan Isi kodenya seperti berikut.import { useState } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { loginUser } from "../redux/actions/auth";
function Login (props) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleForm = e => {
e.preventDefault();
const { dispatch } = props;
dispatch(loginUser(email, password));
};
const { isLoggingIn, loginError, isAuthenticated } = props;
if (isAuthenticated) {
return <Redirect to="/" />
} else {
return (
<div>
<h1>Login</h1>
<form onSubmit={e => handleForm(e)}>
<input
value={email}
onChange={e => setEmail(e.target.value)}
name="email"
type="email"
placeholder="email"
required
/>
<input
value={password}
onChange={e => setPassword(e.target.value)}
name="password"
type="password"
placeholder="password"
required
/>
<hr />
<button type="submit">Login</button>
<hr />
<span>{loginError && ("Email atau Password Salah!")}</span>
<span>{isLoggingIn && ("Sedang login ...")}</span>
</form>
</div>
);
}
}
function mapStateToProps(state){
return {
isLoggingIn: state.auth.isLoggingIn,
loginError: state.auth.loginError,
isAuthenticated: state.auth.isAuthenticated
}
}
export default connect(mapStateToProps)(Login);
Home.js
di folder src/components
.import React from "react";
import { connect } from "react-redux";
import { logoutUser } from "../redux/actions/auth";
class Home extends React.Component {
handleLogout = () => {
const { dispatch } = this.props;
dispatch(logoutUser());
};
render () {
const { isLoggingOut, logoutError } = this.props;
return (
<div>
<h1>Halaman ini dilindungi dengan password.</h1>
<p>Semua routes di sini akan dilindungi.</p>
<button onClick={this.handleLogout}>Keluar</button>
{isLoggingOut && <p>Sedang proses logout...</p>}
{logoutError && <p>Terjadi galat saat logout!</p>}
</div>
);
}
}
function mapStateToProps (state) {
return {
isLoggingOut: state.auth.isLoggingOut,
logoutError: state.auth.logoutError
};
}
export default connect(mapStateToProps)(Home);
src/
routes/protectedRoute.js
yang isinya sebagai berikut.import React from "react";
import { Route, Redirect } from "react-router-dom";
const ProtectedRoute = ({
component: Component,
isAuthenticated,
isVerifying,
...rest
}) => (
<Route
{...rest}
render={props =>
isVerifying ? (
<div />
) : isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
export default ProtectedRoute;
src/Root.js
dengan isi kode sebagai berikut.import { Route, Switch } from "react-router-dom";
import { connect } from "react-redux";
import ProtectedRoute from "./routes/protectedRoute";
import Home from "./components/Home";
import Login from "./components/Login";
function Root (props) {
const { isAuthenticated, isVerifying } = props;
return (
<Switch>
<ProtectedRoute
exact
path="/"
component={Home}
isAuthenticated={isAuthenticated}
isVerifying={isVerifying}
/>
<Route path="/login" component={Login} />
</Switch>
);
}
function mapStateToProps (state) {
return {
isAuthenticated: state.auth.isAuthenticated,
isVerifying: state.auth.isVerifying
};
}
export default connect(mapStateToProps)(Root);
src/App.js
yang menentukan tampilan render pada aplikasi React kita.src/App.js
import React from "react";
import { Provider } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
import configureStore from "./redux/configureStore";
import Root from "./Root";
import './App.css';
Kemudian coba lakukan login dengan email dan password yang telah didaftarkan sebelumnya di Codelab 10. Jika login sukses, maka akan mengarah ke komponen Home seperti pada gambar berikut.
protectedRoute.js
!Selamat, Anda telah berhasil menyelesaikan codelab ini. Semoga mendapatkan ilmu yang bermanfaat.
Silakan cek beberapa sumber belajar lainnya...