state가 크고 복잡하고 여러 state가 결합된 상태에 사용한다.
const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn)
state = 최신 스냅샷 최신값
dispatchFn = 스냅샷 업데이트 함수 여기까진 useState랑 같음
reducerFn = 최신 state 스냅샷을 자동으로 가져오는 함수
initialState = 초기 state
initFn = 초기 함수
import React, { useState } from 'react';
import Card from '../UI/Card/Card';
import classes from './Login.module.css';
import Button from '../UI/Button/Button';
const Login = (props) => {
const [enteredEmail, setEnteredEmail] = useState('');
const [emailIsValid, setEmailIsValid] = useState();
const [enteredPassword, setEnteredPassword] = useState('');
const [passwordIsValid, setPasswordIsValid] = useState();
const [formIsValid, setFormIsValid] = useState(false);
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
setFormIsValid(
event.target.value.includes('@') && enteredPassword.trim().length > 6
);
};
const passwordChangeHandler = (event) => {
setEnteredPassword(event.target.value);
setFormIsValid(
event.target.value.trim().length > 6 && enteredEmail.includes('@')
);
};
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes('@'));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
const submitHandler = (event) => {
event.preventDefault();
props.onLogin(enteredEmail, enteredPassword);
};
return (
<Card className={classes.login}>
<form onSubmit={submitHandler}>
<div
className={`${classes.control} ${
emailIsValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="email">E-Mail</label>
<input
type="email"
id="email"
value={enteredEmail}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
<div
className={`${classes.control} ${
passwordIsValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={enteredPassword}
onChange={passwordChangeHandler}
onBlur={validatePasswordHandler}
/>
</div>
<div className={classes.actions}>
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
Login
</Button>
</div>
</form>
</Card>
);
};
export default Login;
를
import React, { useState, useEffect, useReducer } from 'react';
import Card from '../UI/Card/Card';
import classes from './Login.module.css';
import Button from '../UI/Button/Button';
const emailReducer = (state, action) => {
if (action.type === 'USER_INPUT') {
return { value: action.val, isValid: action.val.includes('@') }
}
if (action.type === 'INPUT_BLUR') {
return { value: state.value, isValid: state.value.includes('@') }
}
return { value: '', isValid: false }
}
const passwordReducer = (state, action) => {
if (action.type === 'USER_INPUT') {
return { value: action.val, isValid: action.val.trim().length > 6 }
}
if (action.type === 'INPUT_BLUR') {
return { value: state.value, isValid: state.value.trim().length > 6 }
}
return { value: '', isValid: false }
}
const Login = (props) => {
const [formIsValid, setFormIsValid] = useState(false);
const [emailState, dispatchEmail] = useReducer(emailReducer, { value: '', isValid: null })
const [passwordState, dispatchPassword] = useReducer(passwordReducer, { value: '', isValid: null })
const { isValid: emailIsValid } = emailState // 불필요한 함수 재실행을 막기 위해 유효성 검사를 통과하면 더이상 검사 안하도록
const { isValid: passwordIsValid } = passwordState // 객체 디스트럭쳐링으로 isValid만 꺼내서 이름을 지정해서 사용
useEffect(()=>{
const identifier = setTimeout(() => {
console.log('checking!')
setFormIsValid(
emailState.isValid && passwordState.isValid
);
},500)
return () => {
console.log('clean!')
clearTimeout(identifier)
}
},[emailIsValid, passwordIsValid])
const emailChangeHandler = (event) => {
dispatchEmail({type: 'USER_INPUT', val: event.target.value})
setFormIsValid(
event.target.value.includes('@') && passwordState.isValid
);
};
const passwordChangeHandler = (event) => {
dispatchPassword({type: 'USER_INPUT', val: event.target.value})
setFormIsValid(
emailState.isValid && event.target.value.trim().length > 6
);
};
const validateEmailHandler = () => {
dispatchEmail({type: 'INPUT_BLUR'})
};
const validatePasswordHandler = () => {
dispatchPassword({type: 'INPUT_BLUR'})
};
const submitHandler = (event) => {
event.preventDefault();
props.onLogin(emailState.value, passwordState.value);
};
return (
<Card className={classes.login}>
<form onSubmit={submitHandler}>
<div
className={`${classes.control} ${
emailState.isValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="email">E-Mail</label>
<input
type="email"
id="email"
value={emailState.value}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
<div
className={`${classes.control} ${
passwordState.isValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={passwordState.value}
onChange={passwordChangeHandler}
onBlur={validatePasswordHandler}
/>
</div>
<div className={classes.actions}>
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
Login
</Button>
</div>
</form>
</Card>
);
};
export default Login;
아직 잘 모르겠다.
더 심플해진 것 같긴하다.