反応ボイラープレートを使用して反応アプリケーションを構築しています。react-boilerplate ジェネレーター機能を使用して認証コンテナーを作成し、それをこのパブリック apiと組み合わせました。メールとパスワードを渡した後、トークンを返します。
トークンをブラウザ localStorage に設定した後、他のコンポーネント/ページにリダイレクトする方法は?
お時間をいただきありがとうございます。
reducers.js
import { fromJS } from 'immutable';
import {
CHANGE_EMAIL,CHANGE_PASSWORD,LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE
} from './constants';
const initialState = fromJS({
email: '',
password: '',
isFetching: false,
isAuthenticated: false,
errorMessage: '',
});
function loginReducer(state = initialState, action) {
switch (action.type) {
case CHANGE_EMAIL:
return state
.set('email', action.email);
case CHANGE_PASSWORD:
return state
.set('password', action.password);
case LOGIN_REQUEST:
return state
.set('isFetching', true)
.set('isAuthenticated', false)
.set('user', action.creds);
case LOGIN_SUCCESS:
return state
.set('isFetching', false)
.set('isAuthenticated', true)
.set('errorMessage', '');
case LOGIN_FAILURE:
return state
.set('isFetching', false)
.set('isAuthenticated', false)
.set('errorMessage', action.message);
default:
return state;
}
}
export default loginReducer;
saga.js
import { call, put, select, takeLatest, takeEvery } from 'redux-saga/effects';
import { withRouter } from 'react-router-dom';
import { LOGIN_REQUEST } from './constants';
import { loginError, receiveLogin } from './actions';
import { postUserLogin } from './api';
import { makeSelectEmail, makeSelectPassword } from './selectors';
export function* loginUser() {
const requestURL = 'https://reqres.in/api/login';
try {
const email = yield select(makeSelectEmail());
const password = yield select(makeSelectPassword());
const creds = {
email: email,
password: password,
}
// test post
const headers = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
}),
};
const users = yield call(postUserLogin,creds);
const raw_token = JSON.stringify(users.token);
const token_id = JSON.parse(raw_token);
console.log("token_id : "+token_id);
yield put(receiveLogin(token_id));
localStorage.setItem('access_token', token_id);
} catch (err) {
console.log(err);
let error;
try {
error = yield err.response.json();
} catch (e) {
error = { errors: [{ detail: `${err.name}: ${err.message}` }] };
}
yield put(loginError(error.error));
}
}
// Individual exports for testing
export default function* defaultSaga() {
// See example in containers/HomePage/saga.js
yield takeEvery(LOGIN_REQUEST, loginUser);
}
index.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { FormattedMessage } from 'react-intl';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';
import { Button, FormGroup, FormControl, ControlLabel, Col, PageHeader, HelpBlock } from "react-bootstrap";
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import { makeSelectLogin,makeSelectEmail, makeSelectPassword, makeSelectErrorMessage, makeSelectIsAuthenticated } from './selectors';
import reducer from './reducer';
import saga from './saga';
import messages from './messages';
import { changeEmail, changePassword, requestLogin } from './actions';
export class Login extends React.Component { // eslint-disable-line react/prefer-stateless-function
componentDidMount() {
if ((this.props.email && this.props.email.trim().length > 0) && (this.props.password && this.props.password.length > 0) ) {
this.props.onSubmitForm();
}
}
renderErrorMessage(){
if(this.props.errorMessage){
return(
<div className="info-red">
{this.props.errorMessage}
</div>
);
}
}
render() {
return (
<div>
<Helmet>
<title>Login</title>
<meta name="description" content="Description of TestPage" />
</Helmet>
<div className="container-fluid">
<div className="row">
<div className="col-md-6 col-md-offset-3">
<div className="login-form">
<form name="loginForm" onSubmit={this.props.onSubmitForm}>
<div className="form-group">
<label htmlFor="email">Email address</label>
<input type='email'
id="email"
className="form-control"
placeholder='Email Address'
required autoFocus
value={this.props.email}
onChange={this.props.onChangeEmail}/>
<FormControl.Feedback />
<HelpBlock>Email cannot be blank</HelpBlock>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input id="password"
type="password"
className="form-control"
placeholder="Password"
required
value={this.props.password}
onChange={this.props.onChangePassword}/>
<FormControl.Feedback />
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">Submit</button>
</div>
</form>
{this.renderErrorMessage()}
</div>
</div>
</div>
</div>
</div>
);
}
}
Login.propTypes = {
email: PropTypes.string,
password: PropTypes.string,
errorMessage: PropTypes.string,
isAuthenticated: PropTypes.bool.isRequired,
onChangeEmail: PropTypes.func,
onChangePassword: PropTypes.func,
onSubmitForm: PropTypes.func,
};
const mapStateToProps = createStructuredSelector({
login: makeSelectLogin(),
email: makeSelectEmail(),
password: makeSelectPassword(),
errorMessage: makeSelectErrorMessage(),
isAuthenticated: makeSelectIsAuthenticated(),
});
function mapDispatchToProps(dispatch) {
return {
onChangeEmail: (evt) => dispatch(changeEmail(evt.target.value)),
onChangePassword: (evt) => dispatch(changePassword(evt.target.value)),
onSubmitForm: (evt) => {
if (evt !== undefined && evt.preventDefault) evt.preventDefault();
const creds = {
email: email.value,
password: password.value,
}
dispatch(requestLogin(creds));
},
fetchPost: (evt) => {
dispatch(fetchPosts());
},
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'login', reducer });
const withSaga = injectSaga({ key: 'login', saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(Login);
action.js
import {
CHANGE_EMAIL,CHANGE_PASSWORD,LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE
} from './constants';
export function changeEmail(email) {
return {
type: CHANGE_EMAIL,
email,
};
}
export function changePassword(password) {
return {
type: CHANGE_PASSWORD,
password,
};
}
export function requestLogin(creds) {
return {
type: LOGIN_REQUEST,
isFetching: true,
isAuthenticated: false,
creds,
};
}
export function receiveLogin(user_token) {
return {
type: LOGIN_SUCCESS,
isFetching: false,
isAuthenticated: true,
token_id : user_token,
};
}
export function loginError(message) {
return {
type: LOGIN_FAILURE,
isFetching: false,
isAuthenticated: false,
message
}
}