この日は6つのファイルにコードを書き足しながら、ユーザーのログイン・ログアウト、そしてナビゲーションバーのリンクを完成させました。
①src/actions/auth.jsに./typesからのインポートとLogin user & Logoutのコードの書き足しを行う
import axios from "axios";
import { setAlert } from "./alert";
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT
} from "./types";
import setAuthToken from "../utils/setAuthToken";
// Load User
export const loadUser = () => async dispatch => {
if (localStorage.token) {
setAuthToken(localStorage.token);
}
try {
const res = await axios.get("./api/auth");
dispatch({
type: USER_LOADED,
payload: res.data
});
} catch (err) {
dispatch({
type: AUTH_ERROR
});
}
};
//Register User
export const register = ({ name, email, password }) => async dispatch => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
const body = JSON.stringify({ name, email, password });
try {
const res = await axios.post("/api/users", body, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
dispatch(loadUser());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: REGISTER_FAIL
});
}
};
//Login User
export const login = (email, password) => async dispatch => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
const body = JSON.stringify({ email, password });
try {
const res = await axios.post("/api/auth", body, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUser());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: LOGIN_FAIL
});
}
};
// Logout / Clear Profile
export const logout = () => dispatch => {
dispatch({ type: LOGOUT });
};
今回書き足しをしたのは、最初のimport {} from "./types"; 部分のLOGIN_SUCCESS, LOGIN_FAIL, LOGOUT 部分です。
そして、コメントアウトしているLogin User & Logoutの部分です。Login Userも部分については、まずはRegister Userからコードを持ってきて、必要ないものを消去したり少し書き換えるだけ、という方法をとりました。
②src/actions/types.js のコードを書き足す。
先程の、src/actions/auth.jsの最初の部分でimport {} from "./types"; とコードを書いた、ということはtypes.jsも書き足しが必要ですよね。というわけで、こちらにもログイン・ログアウト情報などを書き加えました。
export const SET_ALERT = "SET_ALERT";
export const REMOVE_ALERT = "REMOVE_ALERT";
export const REGISTER_SUCCESS = "REGISTER_SUCCESS";
export const REGISTER_FAIL = "REGISTER_FAIL";
export const USER_LOADED = "USER_LOADED";
export const AUTH_ERROR = "AUTH_ERROR";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const LOGOUT = "LOGOUT";
③src/reducers/auth.jsにも、LOGIN_SUCCESS, LOGIN_FAIL, LOGOUTのコードを書き足す
こちらはシンプルで、import {} from "..actions/types"; の部分へのコード書き足しと、switchのcaseの部分への書き足しのみとなりました。
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT
} from "../actions/types";
const initialState = {
token: localStorage.getItem("token"),
isAuthenticated: null,
loading: true,
user: null
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
loading: false,
user: payload
};
case REGISTER_SUCCESS:
case LOGIN_SUCCESS:
localStorage.setItem("token", payload.token);
return {
...state,
...payload,
isAuthenticated: true,
loading: false
};
case REGISTER_FAIL:
case AUTH_ERROR:
case LOGIN_FAIL:
case LOGOUT:
localStorage.removeItem("token");
return {
...state,
token: null,
isAuthenticated: false,
loading: false
};
default:
return state;
}
}
④ component/auth/Login.jsへのコード書き加え(Login.jsの完成)
Login.jsへは沢山コードを書き加えました。最初のimport部分には、Redirect, connect, PropTypes, loginを書き加え、それに合わせて、最後11行、Login.Proptypesから始まるコードを書き加えています。点と点だったものがやっと繋ぎ合わさり、Login.jsファイルは完成となりました!
import React, { Fragment, useState } from "react";
import { Link, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { login } from "../../actions/auth";
const Login = ({ login, isAuthenticated }) => {
const [formData, setFormData] = useState({
email: "",
password: ""
});
const { email, password } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async e => {
e.preventDefault();
login(email, password);
};
if (isAuthenticated) {
return ;
}
return (
//fragment内のコードがブログ上では上手く表示されないため割愛。(Sign in, Login, Sign up部分の表示をするためのコード)
);
};
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
};
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ login }
)(Login);
最初は/dashboardへのリダイレクトが上手くいかず少し焦ったのですが、もう一度書き直しをすることで上手くいきました。
⑤components/auth/Register.jsを完成させる
Register.jsもLogin.jsと同様、import部分に Redirectを書き加えています。
また、const RegisterにはisAuthenticatedを書き加え、'/dashboard'にリダイレクトするようにしました。
最後の方にはconst mapStateToPropsを作成しています。
import React, { Fragment, useState } from "react";
import { connect } from "react-redux";
import { Link, Redirect } from "react-router-dom";
import { setAlert } from "../../actions/alert";
import { register } from "../../actions/auth";
import PropTypes from "prop-types";
const Register = ({ setAlert, register, isAuthenticated }) => {
const [formData, setFormData] = useState({
name: "",
email: "",
password: "",
password2: ""
});
const { name, email, password, password2 } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async e => {
e.preventDefault();
if (password !== password2) {
setAlert("Passwords do not match", "danger");
} else {
register({ name, email, password });
}
};
if (isAuthenticated) {
return ;//Redirectで/dashboardへ。
}
return (
//Fragment内のコードがブログ上で上手く表示されないため割愛。Sign up, Create Your Account, フォームのonSubmit等のコード。
);
};
Register.propTypes = {
setAlert: PropTypes.func.isRequired,
register: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
};
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ setAlert, register }
)(Register);
⑥src/components/layout/Navbar.js ナビゲーションバーにimportとログアウトコード書き加え
Navbar.jsは元々ファイルを作成した時にはシンプルにimport Reactと{Link}周りのコードをを書いていたのみだったのですが、{connect} , PropTypes, {logout}を書き加えました。
また、const Navbarなどでログアウトもできるようにコードを書き加えました。最終的にこのファイルでもpropTYpes mapStateToProps等を利用するようにしています。
import React, { Fragment } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { logout } from "../../actions/auth";
const Navbar = ({ auth: { isAuthenticated, loading }, logout }) => {
const authLinks = (
//onClickでログアウト(割愛)
); const guestLinks = (
//Developers, Register, Loginへのリンク(割愛)
); return (
); }; Navbar.propTypes = { logout: PropTypes.func.isRequired, auth: PropTypes.object.isRequired }; const mapStateToProps = state => ({ auth: state.auth }); export default connect( mapStateToProps, { logout } )(Navbar);
本日の学習の感想(99日目)
ファイルの数が増えてきたのでtreeを書いて全体像を把握しました。割とシンプルなアプリケーションになる予定なのですが、それでもコードは沢山書かなければならないのだなぁという印象です。繰り返しに近いことも多いので慣れてきた部分と、まだはっきりわかっていない部分があるので、復習しながら学習を進めたいです。
次回で、まずは目標としていた100日目に到達します!できなかったことより、できたことを数えていくのが(プログラミングに限らずですが)学習を継続していくコツだと思いました。
現在使用している教材と学習時間:本日の学習時間2.5時間
Udemy:MERN Stack Front To Back: Full Stack React, Redux & Node.js by Brad Traversy
★Section8:React User Authentication
-Lec 42 User Login
-Lec 43 Logout & Navbar Links (ここまで完了。Section8終了)
進捗状況:59%
学習時間2.5時間
~本日は休みにしている教材~
Udemy:The Complete Web Developer: Zero to Mastery by Andrei Neagoie
進捗状況: 92%
★参考にした本★
「React.js & Next.js超入門」掌田津耶乃 (秀和システム)
Section4-1: Reduxを使ってみよう
★参照記事★
Quiita参照記事⇒[axios] axios の導入と簡単な使い方