본문 바로가기
시작/TIL(Today I Learned)

230302 - React - React.Fragment, useRef, Custome Hook

by 백씨네 2023. 3. 2.

오늘 내가 배운 것

1. React.Fragment

2. useRef

3. Custome Hook

 

1. React.Fragment


React를 처음 배울 때 컴포넌트 return에 최상위 엘리먼트는 1개여야 한다는 것을 설명한 적이 있다. 그때 모든 컴포넌트 대해서 `div`를 이용해서 감쌀 경우 원치 않은 div에 감싸지는 경우가 생긴다.

 

<div>
    <div>컴포넌트 1-1</div>
    <div>컴포넌트 1-2</div>
</div>
<div>
    <div>컴포넌트 2-1</div>
    <div>컴포넌트 2-2</div>
</div>

최상위 `div`를 React.Fragment로 감싸게 되면

<React.Fragment>
    <div>컴포넌트 1-1</div>
    <div>컴포넌트 1-2</div>
</React.Fragment>
<React.Fragment>
    <div>컴포넌트 2-1</div>
    <div>컴포넌트 2-2</div>
</React.Fragment>

코드를 작성할 때는 <React.Fragment> 태그가 있지만 실제로 출력되는 엘리먼트 요소는

<div>컴포넌트 1-1</div>
<div>컴포넌트 1-2</div>
<div>컴포넌트 2-1</div>
<div>컴포넌트 2-2</div>

로 생략되어 나온다.

 

<React.Fragment>는 <></> 빈 상태로 작성해서 간단하게 사용할 수 있다.

이를 활용해서 컴포넌트를 만들 때 default로 넣고 사용하는 경우가 많다.

return (
    <>
        <div>컴포넌트 1-1</div>
        <div>컴포넌트 1-2</div>
        <div>컴포넌트 2-1</div>
        <div>컴포넌트 2-2</div>
    </>
)

 

 

 

2. useRef

React Hook 함수중 `useRef`를 이용하여 DOM 요소를 선택하고 싶을 때 사용할 수 있다.

예를 들어 input 태그를 이용해서 해당 input에 focus()를 이용하고 싶을 때 vanilla JS에서는

const userId = document.querySelector("#userId")
userId.focus()

위와 같이 사용했었다.

리액트에서는 함수형 컴포넌트를 사용할 때 위와 같은 방법이 아닌 useRef()를 이용하여 작성한다.

 

const Ref = () => {
    const userId = useRef(null)
    console.log(userId, "최소 렌더시 생성")

    const handleSubmit = (e) => {
        e.preventDefault()
        userId.current.value = ""
        userId.current.focus()
        console.log(userId, "submit 발동시")
    }
    useEffect(() => {
        console.log(userId, "Mount시")
    }, [])

    return (
        <>
            <form onSubmit={handleSubmit}>
                <input type="text" id="userId" ref={userId} />
                <input type="text" id="userPw" />
                <button type="submit"> 확인</button>
            </form>
        </>
    )
}

이를 이용하여

userId.current.focus()

submit 이벤트 발동 시 focus()을 할 수 있다.

 

 

사진을 보면 최초 렌더링을 할 때 userId의 값은 비어있었다.
이후 마운트가 되면서 userId의 상태값이 바뀌고 이때 userId의 값이 대입된 것을 확인할 수 있다.

어느 시점에 값이 할당되어 사용이 가능한지를 알고 적용할 수 있어야 한다.

 

 

 

3. Custom Hook

custom hook을 만드는 가장 큰 목적은 중복된 코드를 제거하기 위해서 만든다.


만약 input 박스가 여러 개 있는 `회원가입 Form`을 리액트를 이용해서 만들 때, 상태를 관리하기 위해서 같은 역할을 하는 함수들이 많아지게 된다.

const [userid, setUserid] = useState("")
const [userpw, setUserpw] = useState("")
const [userNick, setUserNick] = useState("")
const [userName, setUserName] = useState("")

.
.
.

const handleChange = (e) =>{
    e.preventDefault()
    setUserid(e.target.value)
}
const handleChange2 = (e) =>{
    e.preventDefault()
    setUserpw(e.target.value)
}
.
.
.

이러면 변수도 많아지고 이에 따라 이벤트 이름을 공통적으로 짓게 되면 나중에 유지보수, 중복된 코드가 많아지게 된다.

그래서 함수로 따로 관리하여 조금 더 간결하게 코드를 작성할 수 있다.

 

// 컴포넌트
import useInput from "./useInput"

const obj = useInput("")
const obj2 = useInput("")

return (
    <>
        <form onSubmit={handleSubmit}>
            <input type="text" id="userId" ref={userId} {...obj} />
            <input type="text" id="userPw" ref={userPw} {...obj2} />
            <button type="submit"> 확인</button>
        </form>
    </>
)

//
// useInput
import React, { useState } from "react"

const useInput = (inital) => {
    const [value, setValue] = useState(inital)
    const onChange = (e) => {
        setValue(e.target.value)
    }
    return {
        value,
        onChange,
    }
}
export default useInput

 

useInput이라는 함수 하나로 상태를 관리할 수 있기 때문에 중복코드를 제거할 수 있다는 장점이 있다.
그리고 useInput()의 매개변수로 초기 value 값을 설정할 수 있다.

엘리먼트 속성의 {...obj} 부분을 보면 obj는 useInput()인데 return 값이 객체 형태이다.
JS문법을 이용하면 `...` 전개구문(스프레드 연산자)을 이용해서 객체 안에 요소를 다 사용할 수 있다.
그렇기 때문에

 

const obj = useInput("") // {value, onChange}

return <input type="text" id="userId" ref={userId} {...obj} />
//의 내용은 아래

return <input type="text" id="userId" ref={userId} value="" onChange={() => {}} />
// 와 같다.

 

위에 input 내용과 아래의 input 내용은 같다.


 

 

댓글