Hari 26: Auth pada React Native

·

4 min read

Hari 26: Auth pada React Native

Pada series ini kita akan membahas konsep authentikasi pada React Native. Proses login akan terjadi jika user telah terdaftar, kemudian memasukkan akun misal email dan password, jika berhasil login maka simpan token pada storage.

Login

Langsung saja, tambahkan file pages/Login.js yang isinya berikut.

import React, { useState } from "react";
import {
  Container,
  Header,
  Body,
  Title,
  Content,
  Text,
  Form,
  Label,
  Input,
  Button,
  Item,
  Right,
} from "native-base";
import { Link } from "react-router-native";
import { useDispatch } from "react-redux";
import { loginUser } from "../actions/user.action";

const Login = (props) => {
  const dispatch = useDispatch();
  const [email, updateEmail] = useState("");
  const [password, updatePassword] = useState("");

  const storeData = async (token) => {
    try {
      await AsyncStorage.setItem("asrul-dev", token);
    } catch (error) {
      console.warn(error);
    }
  };

  const doLogin = () => {
    dispatch(loginUser({ email, password })).then((res) => {
      const token = res.data.token;
      storeData(token);
    });
  };

  return (
    <Container>
      <Header>
        <Body>
          <Title>Login</Title>
        </Body>
      </Header>
      <Content style={{ padding: 16 }}>
        <Right>
          <Text style={{ fontSize: 32 }}>Login 30 Hari Js</Text>
        </Right>
        <Form>
          <Item floatingLabel>
            <Label>Email</Label>
            <Input onChangeText={(text) => updateEmail(text)} value={email} />
          </Item>
          <Item floatingLabel last>
            <Label>Password</Label>
            <Input
              secureTextEntry={true}
              onChangeText={(text) => updatePassword(text)}
              value={password}
            />
          </Item>

          <Button
            onPress={doLogin}
            style={{
              marginTop: 32,
              marginBottom: 16,
              flex: 1,
              justifyContent: "center",
              alignItems: "center",
            }}
          >
            <Text> Login </Text>
          </Button>
          <Right>
            <Link to={"/register"}>
              <Text> Register Free Now</Text>
            </Link>
          </Right>
        </Form>
      </Content>
    </Container>
  );
};

export default Login;

Kemudian ubah file RouterApp.js menjadi seperti berikut.

import React, { Fragment } from "react";
import { Container, Text, Footer, View, Icon } from "native-base";
import { NativeRouter, Route, Link } from "react-router-native";

import Home from "./pages/Home";
import About from "./pages/About";
import Login from "./pages/Login";
import Register from "./pages/Register";
import { useSelector } from "react-redux";

const RouterApp = () => {
  const auth = useSelector((state) => state.auth);

  return (
    <NativeRouter>
      <Container>
        {!auth.isLogin ? (
          <Fragment>
            <Route exact path="/" component={Login} />
          </Fragment>
        ) : (
          <Fragment>
            <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
            <Footer>
              <Link to="/" underlayColor="blue" style={{ flex: 1 }}>
                <View
                  style={{
                    flex: 1,
                    justifyContent: "center",
                    alignItems: "center",
                  }}
                >
                  <Icon name="home" style={{ color: "white" }} />
                  <Text style={{ color: "white" }}>Home</Text>
                </View>
              </Link>
              <Link to="/about" underlayColor="blue" style={{ flex: 1 }}>
                <View
                  style={{
                    flex: 1,
                    justifyContent: "center",
                    alignItems: "center",
                  }}
                >
                  <Icon name="person" style={{ color: "white" }} />
                  <Text style={{ color: "white" }}>About</Text>
                </View>
              </Link>
            </Footer>
          </Fragment>
        )}
      </Container>
    </NativeRouter>
  );
};

export default RouterApp;

Ubah file actions/user.action.js menjadi seperti berikut.

import axios from "axios";

const baseUrl = `https://warm-refuge-26108.herokuapp.com`;

export const getUsers = () => {
  return async (dispatch) => {
    dispatch({
      type: "GET_USER_REQUEST",
    });
    try {
      const result = await axios.get(baseUrl + `/users`);
      dispatch({
        type: "GET_USER_DONE",
        payload: result.data,
      });
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

export const createUser = (data) => {
  return async (dispatch) => {
    try {
      const result = await axios.post(baseUrl + `/users`, data);
      return result;
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

export const loginUser = (data) => {
  return async (dispatch) => {
    try {
      const result = await axios.post(baseUrl + `/users/login`, data);
      dispatch({
        type: "DO_LOGIN",
        payload: result.data.token,
      });
      return result;
    } catch (error) {
      return 500;
    }
  };
};

export const logoutUser = () => {
  return (dispatch) => {
    try {
      dispatch({
        type: "DO_LOGOUT",
      });
    } catch (error) {
      return 500;
    }
  };
};

Tambahkan file reducers/auth.reducer.js yang isinya seperti berikut.

const initialState = {
  isLogin: false,
  token: null,
};

export default (state = initialState, action) => {
  switch (action.type) {
    case "DO_LOGIN":
      return {
        ...state,
        isLogin: true,
        token: action.payload,
      };
    case "DO_LOGOUT":
      return {
        ...state,
        isLogin: false,
        token: null,
      };
    default:
      return state;
  }
};

Kemudian ubah file helpers/store.js menjadi seperti berikut.

import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";

import Users from "../reducers/user.reducer";
import Auth from "../reducers/auth.reducer";

const combine = combineReducers({
  users: Users,
  auth: Auth,
});

const Store = createStore(combine, applyMiddleware(thunk));
export default Store;

Logout

Ubah file pages/Home.js untuk menambahkan fitur logout sehingga menjadi seperti berikut.

import React, { useEffect } from "react";
import {
  Container,
  Header,
  Body,
  Title,
  Content,
  Text,
  Spinner,
  Card,
  CardItem,
  Left,
  Thumbnail,
  Image,
  Button,
  Icon,
  Right,
  Item,
} from "native-base";
import { useDispatch, useSelector } from "react-redux";
import { getUsers, logoutUser } from "../actions/user.action";
import { AsyncStorage } from "react-native";

const Home = (props) => {
  const dispatch = useDispatch();
  const usersData = useSelector((state) => state.users);

  const doLogout = async (key) => {
    try {
      await AsyncStorage.removeItem(key);
      dispatch(logoutUser());
      return true;
    } catch (exception) {
      return false;
    }
  };

  const logout = () => {
    doLogout("asrul-dev");
  };

  useEffect(() => {
    dispatch(getUsers());
  }, []);

  return (
    <Container>
      <Header>
        <Body>
          <Title>Home</Title>
        </Body>
        <Right>
          <Title onPress={logout}>Logout</Title>
        </Right>
      </Header>
      <Content>
        {usersData.isLoading && <Spinner color="blue" />}

        {usersData.isError && <Spinner color="red" />}

        {usersData.data.map((item, index) => (
          <Card key={index}>
            <CardItem>
              <Left>
                <Thumbnail source={{ uri: item.picture }} />
                <Body>
                  <Text> {item.name} </Text>
                  <Text note> {item.label} </Text>
                </Body>
              </Left>
            </CardItem>
          </Card>
        ))}
      </Content>
    </Container>
  );
};

export default Home;

Hasilnya akan seperti berikut

Hasil Auth