이벤트핸들러, useRef

이벤트 처리 - 기본

자바스크립트에서 배우셨겠지만, 모든 DOM 노드는 click, focus, keydown 등 사용자와의 상호작용에 따라 event 라는 신호를 발생시킨다

사용자가 웹사이트 상에서 버튼을 클릭했다면, 그때는 click 이벤트가 발생하고, 우리는 이 click 이벤트가 발생했을 때 실행할 코드를 설정할 수 있다.

이벤트 발생에 따라 실행될 함수를 설정하는 것을, 이벤트 핸들러 할당이라고 한다.

자바스크립트에서 이벤트 핸들러의 할당은 html 태그에 on이벤트=”실행될함수” 속성을 설정해주는 것으로 할 수 있었다.

리액트 이벤트

리액트는 자바스크립트와 다르게

  • jsx 형태로 {}안에 이벤트 핸들러 명시
  • 이벤트 핸들러는 ()없이 함수명만 명시한다
  • 카멜 케이스로 이벤트 속성 명시

on이벤트=”실행될함수”

리액트는 브라우저 자체의 native event를 활용하는 것이 아니라, 브라우저 간의 호환의 위해서 해당 event를 감싼 synthetic event를 활용한다. 그래서 이벤트 객체의 이름 또한 SyntheticBaseEvent라고 표시되는 것이다.

리액트는 이벤트 핸들러를 태그 자체에 할당하는 것이 아니라, root태그에 할당해놓고 이벤트 위임의 형태로 이벤트 핸들러 함수를 실행시킨다.

이벤트 처리 - 심화

이벤트 버블링

하나의 이벤트 발생시, 해당 요소의 이벤트 핸들러가 작동하고 ,이어서 그 부모 요소의 이벤트 핸들러가 작동하고, 그렇게 최상다느이 요소까지 각 요소에 할당된 핸들러가 작동한다.

리액트도 마찬가지로 이벤트 버블링이 발생한다.

이벤트 위임

동일한 방식으로 여러 요소를 다뤄야 할 때 사용할수 있다. 동일한 작업인데 여러 요소에 각각 이벤트 핸들러를 할당하는 것은 비효율적이다. 여러 요소들의 공통 부모인 요소하나에 이벤트를 설정해놓고, 그 이벤트를 토대로 내부 요소를 관리하면 훨씬 더 효율적인 코드가 된다.

function Menu() {
    const [isClicked, setIsClicked] = useState(false)
    const [menuNumber, setMenuNumber] = useState(null)
    const onClick = (e) => {
        setMenuNumber(e.target.id)
    }
    const toggleMenu = (e) => {
        console.log(e.target, e.currentTarget)
    }
    return (
        <div onClick={onClick}>
            {menuNumber}
            <button id="1">메뉴</button>
            <button id="2">메뉴</button>
            <button id="3">메뉴</button>
        </div>
    )
}

여러개의 버튼에 이벤트를 추가하는 것 보다 div에 이벤트를 집어넣어서 이벤트를 위임하는것이 더 효율적이다.

이벤트 유형

onClick

많이 봐서 알지만, 말 그대로 클릭하면 특정 함수가 실행되도록 하기 위한 이벤트 속성이다.

onChange

input 태그에서 내부 내용이 바뀔 때 실행될 함수를 지정할 수 있다.

function Handlers() {
    const [number, setNumber] = useState(0)
    const changeHandler = (e) => {
        setNumber(e.target.value)
    }
    return (
        <div>
            <input onChange={changeHandler} />
            <p>{number}</p>
        </div>
    )
}

사용자가 입력한 값이 그대로 아래에 출력된다.

onBlur와 onFocus

onFocus는 input 태그에 포커싱되었을 때 실행될 함수를 지정할수 있다.

import React, { useState } from 'react'

function Handlers() {
    const [isFocused, setIsFocused] = useState(false)
    const focusHandler = (e) => {
        setIsFocused(true)
    }

    return (
        <>
            <input onFocus={focusHandler} />
            <p>{isFocused ? '저녁 뭐먹지?' : null}</p>
        </>
    )
}

export default Handlers

onBlur는 포커스가 풀렸을 때 실행될 함수를 지정할수 있다.

 const blurHandler = (e) => {
        setIsFocused(false)
    }
import React, { useState } from 'react'

function Handlers() {
    const [isFocused, setIsFocused] = useState(false)
    const focusHandler = (e) => {
        setIsFocused(true)
    }
    const blurHandler = (e) => {
        setIsFocused(false)
    }

    return (
        <>
            <input onFocus={focusHandler} onBlur={blurHandler} />
            <p>{isFocused ? '저녁 뭐먹지?' : '찜닭게티?'}</p>
        </>
    )
}

export default Handlers

onKeyDown

키를 눌렀을 때 실행될 함수를 지정하는 속성이다.

function Handlers() {
    const KeyHandler = (e) => {
        alert('눌렀습니다!')
    }

    return (
        <div>
            <input onKeyDown={KeyHandler} />
        </div>
    )
}

enter 키만 눌렀을때로 제한을 두고 싶다면 e.key === 'Enter'로 활용하면 된다.

  const KeyHandler = (e) => {
        if (e.key === 'Enter') {
            alert('눌렀습니다!')
        }
    }

    return (
        <div>
            <input onKeyDown={KeyHandler} />
        </div>
    )

onMouserOver와 onMouseOut

onMouseOver는 해당 요소 위로 마우스가 들어왔을 때 실행될 함수를 지정하는 속성이다.

function Handlers() {
    const [isHovering, setIsHovering] = useState(false)
    const MouseOverHandler = (e) => {
        setIsHovering(true)
    }

    return (
        <div onMouseOver={MouseOverHandler}>
            마우스를 올리면?
            <p>{isHovering ? '짜잔!' : null}</p>
        </div>
    )
}

onMouseOut은 해당 요소에서 마우스가 나갔을 때 실행될 함수를 지정하는 속성이다.

import React, { useState } from 'react'

function Handlers() {
    const [isHovering, setIsHovering] = useState(false)
    const MouseOverHandler = () => {
        setIsHovering(true)
    }
    const MouseOutHandler = () => {
        setIsHovering(false)
    }

    return (
        <div onMouseOver={MouseOverHandler} onMouseOut={MouseOutHandler}>
            마우스를 올려볼까요?
            <p>{isHovering ? '짜잔!' : '엥 어디가?'}</p>
        </div>
    )
}
export default Handlers

로그인 화면 만들기

로그인 컴포넌트를 제작한다.

function Login() {
    const doLogin = () => {
        alert('로그인 완료!')
    }
    return (
        <div>
            <input placeholder="아이디를 입력하세요" />
            <input placeholder="비밀번호를 입력하세요" type="password" />
            <button onClick={doLogin}>로그인</button>
        </div>
    )
}

현재 로그인 버튼을 누르면 alert 창이 나타난다.

이벤트 더 추가

로그인을 진행하려면, 유저가 입력한 값을 받아와서 state 형태로 저장하고 해당 state를 백엔드 서버에 보내는 방식으로 구현해야한다.

유저가 작성한 값을 저장하기 위한 state 생성
유저가 인풋을 입력할 때마다 해당 값을 가져와서 setstate를 하도록 작성한다.

 const onUserIdChange = (e) => {
        const { value } = e.target
        setUserId(value)
    }
    const doLogin = () => {
        alert('로그인 완료!')
    }
    return (
        <div>
            <input placeholder="아이디를 입력하세요" value={userId} onChange={onUserIdChange} />
            <input placeholder="비밀번호를 입력하세요" type="password" />
            <button onClick={doLogin}>로그인</button>
        </div>
    )

엔터를 누르면 로그인 되도록 하고 싶다.

onkeyDown 이벤트를 활용

 onKeyDown={(e) => {if (e.key==="Enter") doLogin()}} 
 

유저가 입력한 값을 alert 시켜보고 싶다.

  const onUserIdChange = (e) => {
        setUserId(e.target.value)
    }
    const onUserPwChange = (e) => {
        setUserPw(e.target.value)
    }
      const doLogin = () => {
        alert(`아이디 : ${userId} 비밀번호 : ${userPw} 로그인 완료!'`)
    }
      
      
       return (
        <div>
            <input placeholder="아이디를 입력하세요" value={userId} onChange={onUserIdChange} />
            <input
                placeholder="비밀번호를 입력하세요"
                type="password"
                onKeyDown={(e) => {
                    if (e.key === 'Enter') doLogin()
                }}
                value={userPw}
                onChange={onUserPwChange}
            />
            <button onClick={doLogin}>로그인</button>
        </div>
    )

아이디랑 비밀번호를 하나의 state와 이벤트 핸들러로 만들고 싶다.

useState의 초기 데이터를 객체 형태로 만들어보면 가능하다

아이디와 비밀번호 input 항목에 name과 value 값을 userInput의 객체 내부요소중 하나로 지정하고 해당 값이 변경될 때마다 해당 name의 데이터 값을 변경해주는 방식으로 접근한다.

const [userInput, setUserInput] = useState({ id: '', pw: '' })
    const onUserInputChange = (e) => {
        const { name, value } = e.target
        setUserInput({ ...userInput, [name]: value })
    }
    const doLogin = () => {
        alert(`아이디 : ${userInput.id} 비밀번호 : ${userInput.pw} 로그인 완료!`)
    }
    
    
    return (
        <div>
            <input placeholder="아이디를 입력하세요" value={userInput.id} name="id" onChange={onUserInputChange} />
            <input
                placeholder="비밀번호를 입력하세요"
                type="password"
                onKeyDown={(e) => {
                    if (e.key === 'Enter') doLogin()
                }}
                value={userInput.pw}
                name="pw"
                onChange={onUserInputChange}
            />
            <button onClick={doLogin}>로그인</button>
        </div>
    )

[spread operater 사용시 주의점]
spread operator 는 내부의 값이 어떤 것이 있는지 명확한 경우에만 사용한다.

UseRef 활용하기

특정한 요소의 id처럼 활용할 수 있을 뿐만 아니라 , 변수를 만드는 것에도 사용할수 있는 훅이다.

특정한 버튼이 눌러졌을 때 해당 버튼이 아닌 다른 jsx 요소의 값을 활용하고 싶다면

변수명 = useRef(초기값) 의 형태로 변수를 하나 선언하고, 해당 변수를 특정한 jsx요소에다가 ref={변수명}형태로 할당한다.

이렇게 하면 해당요소는 변수명.current를 통해서 언제든지 접근이 가능해진다. (주의할 점은 반드시! .current를 붙여줘야한다는 것이다!)

function Login() {
    const userId = useRef('')
    const doLogin = () => {
        alert(userId.current.value)
    }

    return (
        <div>
            <input placeholder="아이디를 입력하세요" ref={userId} />
            <button onClick={doLogin}>로그인</button>
        </div>
    )
}
profile
개발자 꿈나무

0개의 댓글