온라인 강의/React 완벽 가이드 [Udemy]

126. useReducer() 훅 사용

유호야 2023. 6. 11. 02:01
반응형

 

이 강의는 못 알아듣겠다! 

이해가 안돼서 생활 코딩의 힘을 빌리기 

 

 

 

 

useState의 경우는 고객이 직접 장부에 기록하는 법을 알아서 실행하는 것이다

 

useReducer의 경우는 고객이 직접 작성하지 않고 주문을 한다 

첫번째 인자는 회계직원 즉 함수, 두번째 인자는 초기값

 

일반적으로 useState를 사용할 때

import React from 'react';
import './style.css';
import { useState, useReducer } from 'react';

export default function App() {
  const [val, setVal] = useState(0);
  const valDown = () => {
    setVal(val - 1);
  };
  const valUp = () => {
    setVal(val + 1);
  };

  const valReset = () => {
    setVal(0);
  }

  return (
    <div>
      <button onClick={valDown}>&lt;</button>
      <button onClick={valReset}>{val}</button>
      <button onClick={valUp}>&gt;</button>
    </div>
  );
}

 

useReducer를 사용할 때

import React from 'react';
import './style.css';
import { useReducer } from 'react';

export default function App() {
  const countReducer = (oldCount, action) => {
    if(action === 'down') {
      return oldCount - 1;
    } else if(action === 'up') {
      return oldCount + 1;
    } else if(action === 'reset') {
      return 0;
    }
  }

  const [count, countDispatch] = useReducer(countReducer, 0);
  
  const valDown = () => {
    countDispatch('down');
  };
  const valUp = () => {
    countDispatch('up');
  };

  const valReset = () => {
    countDispatch('reset');
  }

  return (
    <div>
      <button onClick={valDown}>&lt;</button>
      <button onClick={valReset}>{count}</button>
      <button onClick={valUp}>&gt;</button>
    </div>
  );
}

 

 

useReducer 해당 강의 복습 중 

Email Reducer 

Email Valid 와 set을 함께 묶어서 useRedcuer를 사용해보자

 

1. useReducer 사용

const [emailState, dispatchEmail] = useReducer();

useReducer() 를 이용해서 state와 dispatch를 생성
useReducer 내부에는 함수와 인자가 들어간다.

  const emailReducer = () => {
    return {value: '', isValid: false};
  }

  const [emailState, dispatchEmail] = useReducer(emailReducer, {value: '', isValid: false});

 

state는 최신의 스냅샷이다

이해가 가기 시작했다.

 

즉 useReducer란? 

const [] = useReducer();
// useReducer 선언

const [emailState, dispatchEmail] = useReducer();
// dispatchEmail은  

const [emailState, dispatchEmail] = useReducer(()=>{}, {value: '', isValid: false});
// useReducer는 함수와 객체(인자)를 받는다

const [emailState, dispatchEmail] = useReducer(emailReducer, {value: '', isValid: false});

// 그리고 기존의 setEmail() 함수를 변경한다
dispatchEmail();

dispatchEmail({type: 'USER_INPUT', val: event.target.value});
// 해당 매개변수는 emailReducer 함수에서 처리된다.

const emailReducer = (state, action) => {
	if(action.type === 'USER_INPUT') {
    	return { value: action.val, isValid: action.val.includes('@') }
        // 이 return 값은 어디로 가는 걸까? 
        // useReducer의 두번째 인자 {}
    }
}

 

action과 state의 차이를 더 알아봐야 할 것 같다

 

 

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 Login = (props) => {
  const [enteredEmail, setEnteredEmail] = useState('');
  const [emailIsValid, setEmailIsValid] = useState();
  const [enteredPassword, setEnteredPassword] = useState('');
  const [passwordIsValid, setPasswordIsValid] = useState();
  const [formIsValid, setFormIsValid] = useState(false);

  const emailReducer = (state, action) => {
    console.log('emailReducer 실행중');
    if (action.type === 'USER_INPUT') {
      console.log('user input 실행중');
      return { value: action.val, isValid: action.val.includes('@') }
    } else if (action.type === 'USER_BLUR') {
      return { value: state.value, isValid: state.value.includes('@') }
    }
    return { value: '', isValid: false };
  }

  const [emailState, dispatchEmail] = useReducer(emailReducer, { value: '', isValid: null });

  useEffect(() => {
    console.log('EFFECT RUNNING');

    return () => {
      console.log('EFFECT CLEANUP');
    };
  }, []);

  // useEffect(() => {
  //   const identifier = setTimeout(() => {
  //     console.log('Checking form validity!');
  //     setFormIsValid(
  //       enteredEmail.includes('@') && enteredPassword.trim().length > 6
  //     );
  //   }, 500);

  //   return () => {
  //     console.log('CLEANUP');
  //     clearTimeout(identifier);
  //   };
  // }, [enteredEmail, enteredPassword]);

  const emailChangeHandler = (event) => {
    console.log("hello");
    // setEnteredEmail(event.target.value);
    dispatchEmail({ type: 'USER_INPUT', val: event.target.value })

    setFormIsValid(
      emailState.isValid && enteredPassword.trim().length > 6
    );
  };

  const passwordChangeHandler = (event) => {
    setEnteredPassword(event.target.value);

    setFormIsValid(
      emailState.isValid && event.target.value.trim().length > 6
    );
  };

  const validateEmailHandler = () => {
    // setEmailIsValid(emailState.isValid);
    dispatchEmail({ type: 'USER_BLUR' });
  };

  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={emailState.value}
            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;

 

 

password까지 완료

setIsForm 때문에 한창 헤맷지만 성공

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 Login = (props) => {
  // const [enteredEmail, setEnteredEmail] = useState('');
  // const [emailIsValid, setEmailIsValid] = useState();
  // const [enteredPassword, setEnteredPassword] = useState('');
  // const [passwordIsValid, setPasswordIsValid] = useState();
  const [formIsValid, setFormIsValid] = useState(false);

  const emailReducer = (state, action) => {
    console.log('emailReducer 실행중');
    if (action.type === 'USER_INPUT') {
      return { value: action.val, isValid: action.val.includes('@') }
    } else if (action.type === 'USER_BLUR') {
      return { value: state.value, isValid: state.value.includes('@') }
    }
    return { value: '', isValid: false };
  }

  const passwordReducer = (state, action) => {
    if (action.type === 'PWD_INPUT') {
      console.log(action.val.trim().length > 6);
      return { value: action.val, isValid: action.val.trim().length > 6 };
    } else if (action.type === 'PWD_BLUR') {
      console.log(state.value.trim().length > 6);
      return { value: state.value, isValid: state.value.trim().length > 6 };
    }
    console.log(state.value.trim().length > 6);
    return { value: state.value, isValid: false };
  }

  const [emailState, dispatchEmail] = useReducer(emailReducer, { value: '', isValid: null });
  const [passwordState, dispatchPassword] = useReducer(passwordReducer, { value: '', isValid: null });

  useEffect(() => {
    console.log('EFFECT RUNNING');

    return () => {
      console.log('EFFECT CLEANUP');
    };
  }, []);

  // useEffect(() => {
  //   const identifier = setTimeout(() => {
  //     console.log('Checking form validity!');
  //     setFormIsValid(
  //       enteredEmail.includes('@') && enteredPassword.trim().length > 6
  //     );
  //   }, 500);

  //   return () => {
  //     console.log('CLEANUP');
  //     clearTimeout(identifier);
  //   };
  // }, [enteredEmail, enteredPassword]);

  const emailChangeHandler = (event) => {
    console.log("hello");
    // setEnteredEmail(event.target.value);
    dispatchEmail({ type: 'USER_INPUT', val: event.target.value })

    setFormIsValid(
      emailState.isValid && passwordState.value.trim().length > 6
    );
  };

  const passwordChangeHandler = (event) => {
    dispatchPassword({ type: 'PWD_INPUT', val: event.target.value })
    // setEnteredPassword(event.target.value);

    setFormIsValid(
      emailState.isValid && event.target.value.trim().length > 6
    );
  };

  const validateEmailHandler = () => {
    // setEmailIsValid(emailState.isValid);
    dispatchEmail({ type: 'USER_BLUR' });
  };

  const validatePasswordHandler = () => {
    // setPasswordIsValid(enteredPassword.trim().length > 6);
    dispatchPassword({ type: 'PWD_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;
반응형