JS/React

[React] #9 리액트 Hooks : useState()의 비동기적 속성

emayom 2021. 9. 5. 01:29

오늘은 강의를 들으면서 새롭게 알게 된 점을 작성하려고 한다! 🤔


useState()를 이용해 입력값을 업데이트하고

message로 valid 한 지 여부를 알려주는 예제를 진행했다.

 

startsWith(0)을 phoneNumber으로 검사하려고 했는데

아래 예제를 진행하다 보니 useState()로 상태를 변경한다고 해서 

즉시 업데이트가 되지 않는다는 특성을 확실히 알 수 있었다 ,,,!!!!

그렇기 때문에 0으로 시작하는지 여부와 길이를 확인하기 위해서는 

event.target으로부터 받은 value를 이용하여 직접 확인해야 했다!

 

그리고 html 버튼에는 disabled를 줄 수 있었다 1!!

disabled={true} 이면 버튼을 누를 수 없도록 만드는 속성이었다.

 

마지막으로 input의 value를 직접 리액트 컴포넌트에서 관리하는

controlled(<-> uncontrolled)의 개념에 대해 살짝 알아봤는데

아직까지는 확실하게 이해가 되지 않는다 🤓

 

const root = document.getElementById("root");

const App = () => {
  const [message, setMessage] = React.useState("");
  const [phoneNumber, setPhoneNumber] = React.useState("");
  
  const handleChange = (event) => {  
    //setPhoneNumber(event.target.value);
    //바로 바뀌지않았다. (싱크 안맞음 -> 즉시 변경 x)
      
    if (event.target.value.startsWith(0)) {
      setMessage("Phone Number is valid");
      setPhoneNumber(CURRENT);
      
    } else if (event.target.value.length === 0) {
      setPhoneNumber("");
      setMessage("");
    } else {
      //0으로 시작하는 번호를 입력하다가 모두 지워도 0이 남는 버그를 해결하기 위해
      setPhoneNumber("");
      setMessage("Phone Number should starts with 0");
    }
  };
  
  return (
    <form>
      <label htmlFor="phone">Phone Number : </label>
      <br />
      <input
        id="phone"
        name="phone"
        onChange={handleChange}
        /* controlled : input의 value를 직접 리액트 컴포넌트에서 관리하는 것 */
        value={phoneNumber}
      />
      <br />
      <p>{message}</p>
      <button type="submit" 
              disabled={ 
              	phoneNumber.length === 0 || message !== "Phone Number is valid" 
              }>
        Submit
      </button>
    </form>
  );
};

ReactDOM.render(<App />, root);

 

진행한 예제에 11자 이상이 되면 11자로 자르고 유효성 검사를 실시하도록

그리고 문자나 기호가 포함되면 버튼을 누를 수 없도록 추가해봤다.

 

여기서도 마찬가지로 setValid(true)를 실행해도 즉시 업데이트가 되지 않았고!

유효성 검사에 통과가 되는 번호를 입력해도 버튼이 활성화되지 않았다ㅎㅎㅎㅎ

useState()의 경우 리렌더링이 되기 전까지는 상태를 업데이트한다고 해도 즉시 반영되지 않기 때문이다!

(그래서 즉시 반영이 필요할 때는 useEffect()를 사용,,,)

 

그래서 동기적으로 업데이트가 될 수 있도록 하기 위해 함수형 업데이트를 사용했다.

 

(같은 쉬운 예시 👇🏻)

const [number, setNumber] = React.useState(0);
  
//상태 값이 아닌 함수를 전달
const minus = () => {
	setNumber((prev) => prev - 1);
};
  
//마찬가지로 함수를 전달
const plus = () => {
	setNumber((prev) => prev + 1);
};
  
return (
	<>
      <h1>{number}</h1>
      <button type="button" onClick={plus}>
        +
      </button>
      <button type="button" onClick={minus}>
        -
      </button>
    </>
  );
};

ReactDOM.render(<App />, root);

 

 

마지막으로 반복되는 event.target.value를 CURRENT로 선언하여 사용했다.

 

const root = document.getElementById("root");

const App = () => {
  const [message, setMessage] = React.useState("");
  const [phoneNumber, setPhoneNumber] = React.useState("");
  const [valid, setValid] = React.useState(false);
  
  const validation = /^01([0|1|6|7|8|9]?)?([0-9]{3,4})?([0-9]{4})$/;
  
  const handleChange = (event) => {
    const CURRENT = event.target.value;
    
    //setPhoneNumber(event.target.value);
    //바로 바뀌지않았다. (싱크 안맞음 -> 즉시 변경 x)
    
    //length가 11자 이상이면 유효성 검사
    if (CURRENT.length > 10) {
      setPhoneNumber(CURRENT.slice(0, 11));
      const isValid = "" + CURRENT;
      
      if (validation.test(isValid)) {
        //setValid(true);
        //여기서도 마찬가지로 싱크 안맞음
        //리렌더링이 되어야 업데이트 됨.

    	setValid((valid: boolean) => !valid);
      }
      
    //0으로 시작하면
    } else if (CURRENT.startsWith(0)) {
      setMessage("Phone Number is valid");
      setPhoneNumber(CURRENT);
      
    } else if (CURRENT.length === 0) {
      setPhoneNumber("");
      setMessage("");
      
    } else {
      //0으로 시작하는 번호를 입력하다가 모두 지워도 0이 남는 버그를 해결하기 위해
      setPhoneNumber("");
      setMessage("Phone Number should starts with 0");
    }
  };
  
  
  return (
    <form>
      <label htmlFor="phone">Phone Number : </label>
      <br />
      <input
        id="phone"
        name="phone"
        onChange={handleChange}
        /* controlled : input의 value를 직접 리액트 컴포넌트에서 관리하는 것 */
        value={phoneNumber}
      />
      <br />
      <p>{message}</p>
      <button type="submit" disabled={!valid}>
        Submit
      </button>
    </form>
  );
};

ReactDOM.render(<App />, root);

 

결론 :

오늘은 setState(useState)가 비동기적이라는 것 확실히 알 수 있었다...! 잊지 못할 예제야


 

RegExp.prototype.test() - JavaScript | MDN

test() 메서드는 주어진 문자열이 정규 표현식을 만족하는지 판별하고, 그 여부를 true 또는 false로 반환합니다.

developer.mozilla.org

 

⚠️ 아래 내용은 모두 개인적인 참고 / 기록을 위한 용도입니다. 참고해주시고 편안하게 봐주세요 :)  ⚠️
***    혹시라도 잘못된 정보가 있다면  언제든지 알려주시면 감사하겠습니다  !    ***