iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
0
Modern Web

React.js & Laravel 30天訓練系列 第 6

【Day 6】The implementation of Sign In & Out

好的 昨天我們初步看完component 相關的架構

今天來真的面對專案裡面的功能 那就是登入與登出的詳細實作

首先 我們是如何決定顯示頁面 這在上一篇有提到 containers/App.jsx 實作

	 	// 判斷登入狀態決定回傳component
	 	if (_IsLogin) {
	 		_ResultPage =   <MuiThemeProvider muiTheme={ThemeDefault}>
							  <div>
							    <Header styles={styles.header}
							            handleChangeRequestNavDrawer={this.handleChangeRequestNavDrawer.bind(this)}>
							    </Header>
							    <LeftDrawer navDrawerOpen={this.state._IsDrawerOpen}
							                menus={Data.menus}
							                username="User Admin">
							    </LeftDrawer>
							    <div style={styles.container}>
							      {this.props.children}
							     </div>
							  </div>
							</MuiThemeProvider>
	 	} else {
	 		_ResultPage = <HomePage></HomePage>
	 	}

OK 所以沒有登入的狀態下就是載入 HomePage 這一個component

And then HomePage Component 比較重要的地方在於 多國語言如何實做起來

首先 import 事情不能少

import {translate} from 'react-i18next';

放入要翻譯的Key到相對應的Html Tag

<h2>{t('UsableFeatures')}</h2>

最後,整個 component 要把它 export 出去

export default translate()(HomePage);

好 接下來我們來看如何做登入與登出的動作
首先 登入
當然是排一個去 login component 的 link

<Link to="/login" className="external">
    {t('login')}
</Link>

然後我們來看 Login Component 在做什麼

先把需要import的部分弄進來

// Initial Library
import React from 'react';
import {
  Link
} from 'react-router';
// Materrital UI Library
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Paper from 'material-ui/Paper';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import Checkbox from 'material-ui/Checkbox';
import PersonAdd from 'material-ui/svg-icons/social/person-add';
import Help from 'material-ui/svg-icons/action/help';
import TextField from 'material-ui/TextField';
// 初始樣式設定
import themeDefault from '../../themeConfig';
// 樣式表引入
import styles from '../../styleConfig/LoginPage';

看重點的 components/LoginPage.jsx 如何做登入按鈕的function

<RaisedButton 
label="Login"
primary={true}
style={styles.loginBtn}
onClick={this.props.onSubmitLogin(this.props.Email, this.props.Password)} />

再來看一下 containers/LoginPage.jsx 如何連接

// loading Library
import { connect } from 'react-redux';
// loading Component
import LoginPage_CP from '../../components/LoginPage';
// loading Action
import { UserLogin, changeLoginEmail, changeLoginPwd } from '../../redux/actions/InitialActions';

export default connect(
	// 從這裡把State的狀態值抽出來,然後component那邊就可以用this.props.Email 把它放在function 當成參數來傳
	(state) => ({
		Email: state.getIn(['InitReducer', 'Email']),
		Password: state.getIn(['InitReducer', 'Password'])
	}),
	(dispatch) => ({
		onChangeUserEmail: event => {
			dispatch(changeLoginEmail(event.target.value))
		},
		onChangeUserPassword: event => (
			dispatch(changeLoginPwd(event.target.value))
		),
		onSubmitLogin: (_email, _password) => () => (
			dispatch(UserLogin(_email, _password))
		)
	}),

)(LoginPage_CP);

重點1 : 把你要連結的LoginPAge_CP Component 連結進來
重點2 : 把對應的Action InitialActions 讀取進來
重點3 : 透過connect 你的(state) 抽出來的東西就是 要把state Tree 裡面的值 取出來給component做使用
重點4 : (dispatch) 就是去承接 你component所發出來的function
而 我這邊的function 包含了 Email值的變動 Password值的變動 還有最後送出去做登入的動作

OK 最後我們來看一下 這三個方法我們怎麼執行

// 更換Email
export const changeLoginEmail = () => ({
	type: CHANGE_Email,
	payload: {
		Email: "rd02@458.com.tw"
	}
});
// 更換Password
export const changeLoginPwd = (pwd) => ({
	type: CHANGE_Password,
	payload: {
		Password: pwd
	}
});

帳號與密碼的方法 就是發出相對應的dispatch 去通知reducer 對state tree做更新 修改的動作

然後是我們的登入動作

export const UserLogin = (_email, _password) => {

	var formData = new FormData();
	formData.append("email", _email);
	formData.append("password", _password);

	return (dispatch) => {
		dispatch(showSpinner());
		fetch("http://xxx.xxx.xxx/api/login", {
				method: "POST",
				body: formData
			})
			.then(function(response) {
				return response.json();
			})
			.then(function(jsonData) {
				if (jsonData.IsSuccess) {
					dispatch({
						type: USER_Login_Success,
						payload: {
							Token: jsonData.result,
						}
					});
					localStorage.setItem("LoginData", JSON.stringify({
						'IsLogin': true
					}));
					dispatch(hideSpinner());
					browserHistory.push('/');
				} else {
					alert(jsonData.result);
				}
			})
			.catch(function(e) {
				console.log(e);
			})
	}
};

這裡看起來很多 但簡單說 先把你的帳號密碼包起來
然後透過fetch function 送到後端
成功登入之後 我們呼叫localstorage 去對LoginData做異動 這樣後續就可以拿來作為是否登入的判斷依據
OK 就可以把我們的網頁 用 browserHistory.push('/') 就可以看到我們登入後的畫面

最後 我們來看登出的動作
簡單說 你在Action 裡面只要把它 dispatch 出去
因為他的重點就要更新 state tree

export const userLogout = createAction('USER_Logout');

再來 我們看更新的 Reducer 如何寫

	// 關注User Email Change
	CHANGE_Email: (state, {payload}) => {
		console.log("Reducer : ", payload.Email)
		return state.merge({Email: payload.Email,})
	},
	// 關注User Password Change
	CHANGE_Password: (state, {payload}) => (
		state.merge({Password: payload.Password,})
	),
	// 登入成功
	USER_Login_Success: (state, {payload}) => {
		return state.merge({IsLogin: true, Token: payload.Token});
	},
	// 登出成功
	USER_Logout: (state) => {
		return state.merge({IsLogin: false, Token: "", Email: "", Password: ""});
	}

我想邏輯上應該是很容易理解的
我在寫的時候唯一覺的有不一樣的地方就是
function decoration 的差別
'()' 不需要去做 return
'{}' 就需要去做 return 值才會真的做改變

OK 這就是登入與登出的部分 明天我們就會前進到 相關List Data 的載入


上一篇
【Day 5】HomePage LeftDrawer and Header
下一篇
【Day 7】Semantic UI in React.js by NPM
系列文
React.js & Laravel 30天訓練30

尚未有邦友留言

立即登入留言