const [id, setId] = useState('');
const [pw, setPw] = useState('');
로그인 페이지를 만드는 과정에서 state를 두개를 만들어서 id와 pw를 담아 개별적으로 state 관리했었다.
그러나 리팩토링 checklist에서 "계산 된 속성명"이라는 챕터에서 "하나의 state로 관리할 것"을 지시했다.
이 경우 "계산 된 속성명"을 활용하면 보다 효율적으로 코드를 짤 수 있다.
const [userData, setUserData] = useState({
id: '',
pw: ''
});
두가지 값을 전부 담아서 state로 관리할 userData라는 변수를 사용한다. 초기값으로 객체 형태를 넣어서 객체형 데이터가 들어갈 것임을 암시한다.
const writeUserData = (e) => {
const {name, value} = e.target;
setUserData({...userData, [name]: value});
};
여기서 "e"라는 객체를 "console.log(e)"로 찍어보면 저 이벤트객체에 수많은 속성을 가지고 있는데 위의 코드는 그런 이벤트 객체에서 "name",과 "value"라는 속성을 가져와 활용하겠다는 의미가 된다.
그리고 저 함수를 로그인에서 입력값을 입력할 두<input>
태그의 속성으로 넣으면 콘솔창에서 실시간으로 객체의 형태로 value값이 변할 때마다 그 값을 기록하게 된다.
그리고 setUserData함수에 인자로 들어가는 {...userData, [name]:value}
에서 "...userData"와 같이 전개연산자(스프레드연산자)를 사용하지 않고 setUserData의 인자로 [name]:value만 사용했을 때,
{id:'', pw:''} ←useState에서 설정한 초기값
{id:'1'}
{id:'12'}
{id:'123'}
{pw:'1'}
{pw:'12'}
{pw:'123'}
보다시피 "1", "2", "3"을 id칸에 타이핑하고 다시 "1", "2", "3"을 pw칸에 타이핑하면 해당하는 칸의 value값에만 반응하고 state로 저장하는 것을 알 수 있다.
그렇기 때문에
setUserData({...userData, [name]:value})
라고 state값을 설정하게 되면 같은 작업을 키보드로 반복했을 때,
{id:'', pw:''}
{id:'1', pw:''}
{id:'12', pw:''}
{id:'123', pw:''}
{id:'123', pw:'1'}
{id:'123', pw:'12'}
{id:'123', pw:'123'}
와 같이 이전의 다른 칸에서 입력된 값도 state로 보관하게 된다. 이렇게 하면 "마지막으로 보관된 두 칸의 state값에 새로 추가되는 state를 추가하여 저장하겠다."는 의미가 된다.
참고로 이 "name"이라는 속성은 <input>
태그에서만 활용할 수 있다.
원래는
const isValid = () => {
return id.include('@') && pw.length > 5;
}
라고 해서 해당함수를 특정 태그에 대한 속성값으로 추가하여 true/false 반환값에 따라서 버튼을 조작했다면 사실은
isValid = id.include('@') && pw.length > 5;
로 함수선언이 아닌 변수처리 해서 활용해도 좋다.이렇게 해도 같은 동작을 한다. &&연산자로 묶인 두 연산이 "true"값을 가지면 전체 변수도 true값을 가지게 되기 때문에.
이것을 버튼태그에 속성된 disabled에
disable={!isVaild}
로 사용하면 된다.