Rental Application (React & Spring boot Microservice) - 24 : Redux
55197 ワード
#1 LoginPage
redixを適用する前に、LoginPageとRegisterPageを作成します.
共同で使用するbuttonとinputを作成します.
import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palettes';
const StyledInput = styled.input`
width: 100%;
height: 40px;
border: 2px solid #aaa;
border-radius: 4px;
margin: 8px 0;
outline: none;
padding: 8px;
box-sizing: border-box;
transition: .3s;
&:focus {
border-color: ${ palette.blue[2] };
box-shadow: 0 0 8px 0 ${ palette.blue[2] };
}
`;
const Input = props => <StyledInput { ...props } />
export default Input;
const Input = props => <StyledInput { ...props } />
において、propsは、name、onChange、valueなどの要素を呼び出すときに受信されるパラメータであり、これは、これらのパラメータをStyledInputに同じように入れることを意味する.import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palettes';
const StyledButton = styled.button`
width: 100%;
height: 50px;
border-radius: 4px;
border: 2px solid ${palette.blue[1]};
margin: 8px 0;
padding: 8px;
box-sizing: border-box;
transition: .3s;
background-color: #ffffff;
color: ${palette.blue[1]};
font-size: 20px;
`;
const BorderButton = props => <StyledButton { ...props } />
export default BorderButton;
import React from 'react';
import styled, { css } from 'styled-components';
import palette from '../../lib/styles/palettes';
const StyledButton = styled.button`
width: 100%;
height: 50px;
border-radius: 4px;
border: none;
margin: 8px 0;
outline: none;
padding: 8px;
box-sizing: border-box;
transition: .3s;
background-color: ${palette.blue[1]};
color: #ffffff;
font-size: 20px;
&:hover {
width: 100%;
height: 50px;
border-radius: 4px;
border: none;
margin: 8px 0;
outline: none;
padding: 8px;
box-sizing: border-box;
transition: .3s;
background-color: ${palette.blue[2]};
color: #ffffff;
font-size: 20px;
}
${
props =>
props.red &&
css`
background: ${ palette.red[0] };
&: hover {
background: ${ palette.red[1] };
}
`
}
`;
const FullButton = props => <StyledButton { ...props } />
export default FullButton;
共通に使用する構成部品が作成されている以上、次のディレクトリを作成してLoginPageを作成します.import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palettes';
const AuthTemplateBlock = styled.div`
left: 0;
top: 0;
bottom: 0;
right: 0;
background: ${ palette.gray[2] };
padding-top: 130px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const WhiteBox = styled.div`
box-shadow: 0 0 8px rgba(0, 0, 0, 0.025);
padding: 2rem;
width: 80%;
background: white;
border-radius: 2px;
`;
const AuthTemplate = ({ children }) => {
return(
<AuthTemplateBlock>
<WhiteBox>
{ children }
</WhiteBox>
</AuthTemplateBlock>
);
};
export default AuthTemplate;
AutheTemplateBlockはAutheForm素子を保護するための素子である.import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import palette from '../../lib/styles/palettes';
import FullButton from '../common/FullButton';
import BorderButton from '../common/BorderButton';
import Input from '../common/Input'
const AuthFormBlock = styled.div`
h3 {
margin: 0;
color: ${ palette.gray[8] };
margin-bottom: 1rem;
}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const Header = styled.div`
margin-top: 20px;
margin-bottom: 30px;
width: 60%;
font-size: 25px;
padding-left: 10%;
color: ${palette.blue[2]};
font-weight: bold;
`;
const ErrorMessage = styled.div`
color: red;
text-align: center;
font-size: 14px;
margin-top: 1rem;
`;
const textMap = {
login: 'login',
register: 'register'
};
const AuthForm = ({
type,
form,
onSubmit,
error
}) => {
const text = textMap[type];
return(
<AuthFormBlock>
{ text === 'login' ? (
<>
<Header>
물건 대여 플랫폼에 <br />
오신 것을 환영합니다!
</Header>
<form onSubmit={ onSubmit }>
<Input
autoComplete="email"
name="email"
placeholder="E-mail"
value={ form.email }
/>
<Input
autoComplete="new-password"
name="password"
placeholder="Password"
type="password"
value={ form.password }
/>
{ error && <ErrorMessage>{ error }</ErrorMessage>}
<FullButton>
Login
</FullButton>
<BorderButton>
<Link to="/auth/RegisterPage">
Sign Up
</Link>
</BorderButton>
</form>
</>
) : (
<>
<Header>
물건 대여 플랫폼에 <br />
처음 오셨군요!
</Header>
<form onSubmit={ onSubmit }>
<Input
autoComplete="email"
name="email"
placeholder="이메일을 입력해주세요"
value={ form.email }
/>
<Input
autoComplete="new-password"
name="password"
placeholder="비밀번호를 입력해주세요"
type="password"
value={ form.password }
/>
<Input
autoComplete="new-password"
name="passwordConfirm"
placeholder="비밀번호를 재입력해주세요"
type="password"
value={ form.passwordConfirm }
/>
<Input
autoComplete="nickname"
name="nickname"
placeholder="닉네임을 입력해주세요"
value={ form.nickname }
/>
<Input
autoComplete="phoneNumber"
name="phoneNumber"
placeholder="'-'를 제외하고 핸드폰 번호를 입력해주세요"
value={ form.phoneNumber }
/>
{ error && <ErrorMessage>{ error }</ErrorMessage>}
<FullButton>
Sign Up
</FullButton>
</form>
</>
)}
</AuthFormBlock>
);
};
export default AuthForm;
ログインとコストでよく使用されるフォーム.ここでは三重演算子を用い,typeをパラメータとしてloginとregisterの間で対応するフォームをそれぞれ呼び出す.import React, { useState } from 'react';
import { withRouter } from 'react-router-dom';
import AuthForm from './AuthForm';
const LoginForm = ({ history }) => {
const [error, setError] = useState(null);
const onSubmit = e => {
// Login Button EventListener
e.preventDefault();
};
return (
<AuthForm
type='login'
form={ form }
onSubmit={ onSubmit }
error={ error }
/>
);
};
export default withRouter(LoginForm);
import React from 'react';
import AuthTemplate from '../components/auth/AuthTemplate';
import LoginForm from '../components/auth/LoginForm';
import HeaderTemplate from '../components/common/HeaderTemplate';
const LoginPage = () => {
return(
<>
<HeaderTemplate />
<AuthTemplate>
<LoginForm />
</AuthTemplate>
</>
);
};
export default LoginPage;
ログインページが作成され、アプリケーションがルーティング機能を有効にします.jsに入れてimport React from 'react';
import { Route } from 'react-router-dom';
import HomePage from './pages/HomePage';
import LoginPage from './pages/LoginPage';
import MyPage from './pages/MyPage';
import RegisterPage from './pages/RegisterPage';
const App = () => {
return(
<>
...
<Route
component={ LoginPage }
path="/auth/LoginPage"
exact
/>
</>
);
};
export default App;
http://localhost:3000/auth/LoginPage道。に入ってログインページを確認しますよく撮れている様子が見られますそれでは、これを利用して会員登録ページを作成しましょう
#2 RegisterPage
import React from 'react';
import AuthForm from './AuthForm';
import { withRouter } from 'react-router-dom';
const RegisterForm = ({ history }) => {
// Handler that registers form
const onSubmit = e => {
e.preventDefault();
};
return (
<AuthForm
type='register'
form={ form }
onSubmit={ onSubmit }
/>
);
};
export default withRouter(RegisterForm);
import React from 'react';
import AuthTemplate from '../components/auth/AuthTemplate';
import RegisterForm from '../components/auth/RegisterForm';
import HeaderTemplate from '../components/common/HeaderTemplate';
const RegisterPage = () => {
return (
<>
<HeaderTemplate />
<AuthTemplate>
<RegisterForm />
</AuthTemplate>
</>
);
};
export default RegisterPage;
import React from 'react';
import { Route } from 'react-router-dom';
import HomePage from './pages/HomePage';
import LoginPage from './pages/LoginPage';
import MyPage from './pages/MyPage';
import RegisterPage from './pages/RegisterPage';
const App = () => {
return(
<>
...
<Route
component={ LoginPage }
path="/auth/LoginPage"
exact
/>
<Route
component={ RegisterPage }
path="/auth/RegisterPage"
exact
/>
</>
);
};
export default App;
ログイン、登録ページのcssが完了した以上、redoxを使用して各ページのInputの状態を管理します.
#3 Redux
これはreduxに関する文章です.
https://velog.io/@biuea/LifeSports-ApplicationReactNative-Node.js-7.-Redux
以下のパッケージをインストールします.
npm install immer react-redux redux redux-actions redux-devtools-extension
changeFieldでは、initializeFormアクション関数を定義します.テキストを入力すると、これらのアクション関数の役割は、テキスト要素の状態をショップに保存し、状態を初期化することです.import { createAction, handleActions } from "redux-actions";
import produce from 'immer';
const CHANGE_FIELD = 'auth/CHANGE_FIELD';
const INITIALIZE_FORM = 'auth/INITIALIZE_FORM';
export const changeField = createAction(
CHANGE_FIELD, ({
form,
key,
value
}) => ({
form,
key,
value,
}),
);
export const initializeForm = createAction(INITIALIZE_FORM, form => form);
const initialState = {
register: {
email: '',
password: '',
passwordConfirm: '',
nickname: '',
phoneNumber: '',
},
login: {
email: '',
password: '',
}
};
const auth = handleActions(
{
[CHANGE_FIELD]: (state, { payload: { form, key, value }}) =>
produce(state, draft => {
draft[form][key] = value;
}),
[INITIALIZE_FORM]: (state, { payload: form }) => ({
...state,
[form]: initialState[form],
}),
},
initialState,
);
export default auth;
import { combineReducers } from "redux";
import auth from './auth';
const rootReducer = combineReducers(
{
auth,
},
);
export default rootReducer;
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from './modules';
import { BrowserRouter } from 'react-router-dom';
const store = createStore(
rootReducer,
composeWithDevTools()
);
ReactDOM.render(
<Provider store={ store }>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
reportWebVitals();
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { changeField } from '../../modules/auth';
import AuthForm from './AuthForm';
const LoginForm = ({ history }) => {
const [error, setError] = useState(null);
const dispatch = useDispatch();
const { form } = useSelector(({ auth }) => ({
form: auth.login,
}));
// For changing input, handler
const onChange = e => {
const {
value,
name
} = e.target;
dispatch(
changeField({
form: 'login',
key: name,
value
})
);
};
const onSubmit = e => {
// Login Button EventListener
e.preventDefault();
};
return (
<AuthForm
type='login'
form={ form }
onChange={ onChange }
onSubmit={ onSubmit }
error={ error }
/>
);
};
export default withRouter(LoginForm);
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { changeField } from '../../modules/auth';
import AuthForm from './AuthForm';
import { withRouter } from 'react-router-dom';
const RegisterForm = ({ history }) => {
const dispatch = useDispatch();
const { form } = useSelector(({ auth }) => ({
form: auth.register,
}));
// For changing input, handler
const onChange = e => {
const { value, name } = e.target;
dispatch(
changeField({
form: 'register',
key: name,
value
})
);
};
// Handler that registers form
const onSubmit = e => {
e.preventDefault();
if(password !== passwordConfirm) {
return;
}
};
return (
<AuthForm
type='register'
form={ form }
onChange={ onChange }
onSubmit={ onSubmit }
/>
);
};
export default withRouter(RegisterForm);
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import palette from '../../lib/styles/palettes';
import FullButton from '../common/FullButton';
import BorderButton from '../common/BorderButton';
import Input from '../common/Input'
...
const AuthForm = ({
type,
form,
onChange,
onSubmit,
error
}) => {
const text = textMap[type];
return(
<AuthFormBlock>
{ text === 'login' ? (
<>
<Header>
물건 대여 플랫폼에 <br />
오신 것을 환영합니다!
</Header>
<form onSubmit={ onSubmit }>
<Input
autoComplete="email"
name="email"
placeholder="E-mail"
onChange={ onChange }
value={ form.email }
/>
<Input
autoComplete="new-password"
name="password"
placeholder="Password"
type="password"
onChange={ onChange }
value={ form.password }
/>
{ error && <ErrorMessage>{ error }</ErrorMessage>}
<FullButton>
Login
</FullButton>
<BorderButton>
<Link to="/auth/RegisterPage">
Sign Up
</Link>
</BorderButton>
</form>
</>
) : (
<>
<Header>
물건 대여 플랫폼에 <br />
처음 오셨군요!
</Header>
<form onSubmit={ onSubmit }>
<Input
autoComplete="email"
name="email"
placeholder="이메일을 입력해주세요"
onChange={ onChange }
value={ form.email }
/>
<Input
autoComplete="new-password"
name="password"
placeholder="비밀번호를 입력해주세요"
type="password"
onChange={ onChange }
value={ form.password }
/>
<Input
autoComplete="new-password"
name="passwordConfirm"
placeholder="비밀번호를 재입력해주세요"
type="password"
onChange={ onChange }
value={ form.passwordConfirm }
/>
<Input
autoComplete="nickname"
name="nickname"
placeholder="닉네임을 입력해주세요"
onChange={ onChange }
value={ form.nickname }
/>
<Input
autoComplete="phoneNumber"
name="phoneNumber"
placeholder="'-'를 제외하고 핸드폰 번호를 입력해주세요"
onChange={ onChange }
value={ form.phoneNumber }
/>
{ error && <ErrorMessage>{ error }</ErrorMessage>}
<FullButton>
Sign Up
</FullButton>
</form>
</>
)}
</AuthFormBlock>
);
};
export default AuthForm;
上のコードのように各InputにonChangeを入れるstateがstoreで良好に保存されるように、次のクロムツールをインストールします.https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?page=1&hl=ko&itemlang=en-GB
よく保存されているのが見えます.次の記事ではauth-serviceに関連付けて、実際の登録とログインを行います.
リファレンス
Reference
この問題について(Rental Application (React & Spring boot Microservice) - 24 : Redux), 我々は、より多くの情報をここで見つけました https://velog.io/@biuea/Rental-Application-React-Spring-boot-Microservice-24-Reduxテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol