React-6 (23/03/02)

nazzzo·2023년 3월 5일
0

1. useRef() 사용법

리액트에서 html 요소를 선택하고 싶을 때는
document객체의 querySelectorgetElement 선택자를 사용하는 것을 지양합니다
(컴포넌트가 HTML로 렌더링 되기 전에는 DOM 요소에 접근이 불가능하기 때문에)

대신 리액트는 자바스크립트 선택자를 대체하는 기능으로 useRef()라는 함수를 제공하고 있습니다

먼저 예제 코드부터 살펴보겠습니다


import React, { useRef } from 'react';

const Ref = () => {
    const input = useRef(null) // { current: null }
    console.log(input)

    console.log(input)
    return (
        <>
            <input type="text" name="username" id="username" />
            <button>Focus</button>
        </>
    )
}

export default Ref

useRef()를 사용하면 최초 렌더링이 되었을 때 input에 접근이 가능해집니다
(클래스형 컴포넌트에서 componentDidMount가 되었을 때)


import React, { useRef, useEffect } from 'react';

    useEffect(() => {
        console.log(input.current)
    },[])
const Ref = () => {
    const input = useRef(null) // { current: null }

    const handleSubmit = (e) => {
        e.preventDefault()
        console.log("submit :", input.current)
    }

    useEffect(() => {
        console.log("componentDidMount :", input.current)
    },[])


    return (
        <>
        <form onSubmit={handleSubmit}>
            <input type="text" name="username" id="username" ref={input} />
            <button type="submit">Focus</button>
        </form>
        </>
    )
}

+)

    const obj = {name: "username", id: "username"}

    return (
        <>
        <form onSubmit={handleSubmit}>
            <input type="text" {...obj} ref={input} />
            <button type="submit">Focus</button>
        </form>
        </>
    )
}
    const submit = { onSubmit: handleSubmit}

    return (
        <>
        <form {...submit}>
            <input type="text" ref={input} />
            <button type="submit">Focus</button>
        </form>
        </>
    )

↑ 이런 식의 사용도 가능합니다
여기서 {...obj}, {...submit}의 중괄호({})는 객체가 아닌,
이 안에서 JSX 문법을 사용하겠다는 선언적 의미입니다
(앞으로 자주 사용게 될 방식이니 잘 알아둡시다)



2. React.Fragment


const App = () => {
    return (
        <React.Fragment>
            <div>Hello</div>
            <div>World</div>
        </React.Fragment>
    )
}

리액트에서 하나의 컴포넌트에 두 개 이상의 엘리먼트를 최상위에 놓는 것은 붉가능합니다
그런데 리액트 컴포넌트를 다루다보면 이러한 엘리먼트들을 감싸는 상위 엘리먼트를 만들고 싶지 않을 경우가 생길 때가 종종 있습니다
이 때, 리액트가 제공하는 Fragment를 사용하면 DOM에 별도의 노드를 추가하지 않고 여러 자식을 그룹화할 수 있습니다

*리액트가 버전업이 되면서 빈 꺽쇠(<>, </>)로 감싸도 똑같이 작동합니다

<>
  <div>Hello</div>
  <div>World</div>
</>



3. 커스텀 훅(Custom Hook)

컴포넌트를 만들다보면 하나의 컴포넌트에서 이벤트를 관리할 함수가 과다해지는 경우가 생깁니다
특히 로그인이나 회원가입 페이지를 만들 때가 그렇습니다

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

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

  return (
    <>
      <form {...submit}>
        <input type="text" name="userid" value={userid} onChange={handleChange} />
        <input type="text" name="userpw" value={userpw} onChange={handleChange2} />
      </form>
    </>
  );
};

이러한 경우 코드의 낭비를 막기 위해 커스텀 훅을 사용할 수 있습니다
같은 패턴으로 실행될 코드와 상태관리를 따로 함수로 빼서 쓰기 위해 사용합니다
특히 인풋 박스를 다룰 때 자주 사용하게 됩니다

함수 생성

const useInput = (initialValue) => {
    const [value, setValue] = useState("")
    const Onchange = (e) => {
        setValue(e.target.value)
    } 

    return {
        value,
        onChange,
    }
}

export default useInput

불러와서 사용하기

import useInput from "./useInput"

const obj4 = useInput() // {value:"", }


  return (
    <>
      <form {...submit}>
        <input type="text" {...obj} ref={input} className={inputStyle.username} />

        <input type="text" name="userid" {...obj4} />
        <input type="text" name="userpw" {...obj4} />
        <button type="submit">Focus</button>
      </form>
    </>
  );
};

*리턴이 컴포넌트가 아닌 객체가 됩니다

예제2

[useInput.jsx]

import React, { useState } from 'react'


const useInput = (initialValue) => {
    const [value, setValue] = useState(initialValue)

    const onChange = (e) => {
        setValue(e.target.value)
    }

    return {value, onChange}
}

export default useInput

[ref.jsx]

import useInput from "./useInput"

const Ref = () => {
  const input = useRef(null); // { current: null }
  const obj2 = useInput("hello world1") // { value: 'hello world'}
  const obj3 = useInput("hello world2")
  const obj4 = useInput("hello world3")
  const obj5 = useInput("hello world4")


  
  ...
  
  return (
            <input type="text" {...obj2} />
    		<input type="text" {...obj3} />
    		<input type="text" {...obj4} />
    		<input type="text" {...obj5} />
    )

if (obj2.value === obj3.value) {}

이런 식으로 상태관리를 각각 할 수 있다는 장점

3. 리액트에서 CSS 적용하기


싱글 페이지 어플리케이션에서 여러 CSS 파일을 적용하려면 어떻게 해야 할까요
우선 기존 방식인 url 변경을 통한 재요청은 불가능합니다

이에 대해서는 여러가지 방법론이 존재합니다


  1. 인라인 스타일 사용하기

가상DOM 태그에 직접 스타일을 먹일 수 있습니다
자주 사용하는 방식은 아닙니다

  1. style-loader

관련 패키지 설치

npm install style-loader

환경설정

**웹팩 환경 설정**
```js
    module: {
        rules: [
            {
                test: /\.jsx?/,
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env","@babel/preset-react"]
                }
            },
            // 스타일 로더 추가
            {
                test: /\.css/,
                use: ["style-loader"],
            },
        ],
    },



적용하기
```js
import "../public/index.css"

↑ import 문으로 파일을 불러와서 사용해야 합니다

style-loader를 사용하면 해당 경로의 css 파일을 함께 번들링합니다
(렌더링되었을 때 <head> 안에 <style> 태그가 담기는 형태로 변환됩니다)

단점

  • 스타일 적용이 겹치는 요소에 대해 상위 컴포넌트의 스타일이 아래에 적용됩니다
    (내부적으로 <App />이 가장 나중에 렌더링되기 때문)
  1. css-loader

관련 패키지 설치

npm install css-loader
npm install mini-css-extract-plugin

환경설정

const MiniCssExtractPlugin = require('mini-css-extract-plugin')


    plugins: [
        ...,
        new MiniCssExtractPlugin({ filename: "index.css" })
    ],
    // 바벨 관련 설정
    module: {
        rules: [
            ...,
            {
                test: /\.css/,
                use: [MiniCssExtractPlugin.loader,"css-loader"],
            },
        ],
    },

css-loader를 사용하면 header 태그 안에 css 태그를 적용할 파일이 연결된 link 태그가 생성됩니다
(css 파일이 하나로 통합되어 index.css 파일 안에 담기는 형태입니다)

단점

  • 이 방식 역시 모든 css 파일이 하나로 통합되면서 적용되기 때문에 같은 선택자를 여러번 사용할 경우
    가장 하단의 선택자에 대한 스타일만 적용됩니다
  1. css-module

[input.module.css]

.username {
    width: 300px;
    padding: 7px 14px;
    border: 1px solid #333;
    font-size: 12px;
    color: #999;
}

적용

import inputStyle from "../public/input.module.css"

<input type="text" {...obj} ref={input} className={inputStyle.username} />

css 파일을 모듈화해서 필요한 요소에만 import로 불러온 스타일을 적용하는 방식으로 사용합니다

단점

  • 모듈화된 CSS 파일이 과하게 많아질 수 있습니다



  1. Styled-Component

css-in-js

Styled-Component를 사용하려면 별도의 라이브러리를 설치해야 합니다

npm install process
npm install styled-components

환경설정

const webpack = require('webpack')

    plugins: [
        new HtmlWebpackPlugin({
            template: 'index.html', // 원본
            filename: 'index.html' // 번들링될 파일 이름
        }),
        new MiniCssExtractPlugin({ filename: "index.css" }),
        new webpack.ProvidePlugin({
            process: "process/browser",
        })
    ],

적용

import styled from "styled-components"


// CSS가 적용된 컴포넌트를 만드는 것
const Div = styled.div`
    background: ${ props => props.background === "blue" ? "blue" : "red" };
`

const Button = styled.button`
    display: inline-block;
    width: ${props => props.size + 'px'};
    padding: 7px 14px;
    justify-content: center;
    align-items: center;
    background-color: #000;
    color: #fff;
    font-weight: Bold;
    border: none;
    outline: none;

    &:hover {
        background-color: #666;
    }
`

const Style = () => {
    return (
        <>
            <Div background="blue">Hello</Div>
            <Div>World</Div>
            <Button size="300">버튼</Button>
        </>
    )
}
export default Style

장점:

  • 리액트 컴포넌트 작업과 CSS 처리를 동시에 적용할 수 있습니다
  • 스타일을 props로 전달할 수도 있습니다
    (스타일을 이벤트에 따라 가변적으로 처리하거나 반복문 형태로 적용하는 것도 가능합니다)
  • 현재 현직에서 가장 많이 사용되는 방식입니다

*vscode 확장프로그램 vscode-styled-components 설치를 추천합니다



0개의 댓글