[리엑트를 다루는 기술] Chapter 08 : Hooks

iGhost·2021년 8월 30일
post-thumbnail

함수형 컴포넌트에서도

  • 상태 관리를 할 수 있는 useState
  • 렌더링 직후 작업을 설정하는 useEffect
  • 을 제공한다

useState란?

  1. useState를 이용해 하나의 상태를 관리하기 위해선..?

    ⇒ 하나의 상태에 useState 를 이용함

  2. useState를 이용해 여러개의 상태를 관리하기 위해선..?

    ⇒ useState를 여러번 사용하면 된다.

useEffect란?

useEffect는 컴포넌트가 렌더링 될 때마다 특정 작업을 수행할수 있도록 해준다.

1. 마운트 될때만 사용하고 싶을때

useEffect(()=> {
	해당 함수
},[]);
  • 화면 맨 처음 실행될 때만 실행하고, 업데이트 될떄는 실행하지 않을려면 함수의 두 번째 파라미터로 비어있는 배열을 주면 된다.

2. 특정 값이 업데이트 될때만 실행하고 싶을때.

useEffect(()=> {
	해당 함수(특정값)
},[특정값]);

3. 뒷정리 하기

useEffect는 기본적으로 랜더링되고 난 직후

하지만, 컴포넌트가 언마운트되기 전이나, 업데이트되기 직전에 어떤 작업을 수행하고 싶다면?

⇒ 뒷정리 함수를 반환해야한다

Info.js

import { render } from '@testing-library/react';
import React, { useState, useEffect } from 'react'

function Info() {
    const [name, setName] = useState('');
    const [nickName, setNickName] = useState('');
    useEffect(() => {
        console.log('effect')
        console.log(name);
        return () => {
            console.log('clean up'); // 컴포넌트가 언마운트 되기전(즉 APP.js에 조건에 의해서 컴포넌트가 닫힐때 나옴)
            console.log(name);
        };
    }, [name])

    const onChangeName = e => {
        setName(e.target.value);
    };

    const onChangeNickName = e => {
        setNickName(e.target.value);
    };

    return (
        <div>
            <div>
                <input
                    value={name}
                    onChange={onChangeName}
                />
                <input
                    value={nickName}
                    onChange={onChangeNickName}
                />
            </div>
            <div>
                <div>
                    <b>이름:</b> {name}
                </div>
                <div>
                    <b>닉네임:</b> {nickName}
                </div>
            </div>
        </div>
    )
}

export default Info

App.js

function App() {
  const [visible, setvisible] = useState(false)
  return (
    <div>
      <button
        onClick={() => {
          setvisible(!visible);
        }}
      >
        {visible ? '숨기기' : '보이기'}
      </button>
      <hr />
      {visible && <Info />} // 조건에 따라 컴포넌트가 마운트 , 언마운트 된다
    </div>
  );
}

export default App;

useReducer

useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 설정 가능

리덕스라는 개념에서 나온다

구동방식

  • 현재 상태, 업데이트를 위해 필요한 정보를 담은 액션값을 전달 받는다
  • 새로운 상태를 반환한다

⇒ 불변성 유지

function reuducer(state, action){
return { ...} // 새로운 상태

{
	type: 'INCREMENT", // 다른 값이 필요하면 추가로 들어간다.
}
  • type은 어떤 액션인지 알려주는 필드이다.

카운터 구현하기

import React, { useReducer } from 'react'

function reducer(state, action) {
    switch (action.type) {
        case 'INCREMENT':
            return { value: state.value + 1 };
        case 'DECREMENT':
            return { value: state.value - 1 };
        default:
            return state;
    }
}
// 리듀서 함수를 만들어서 dispatch 함수로 받아오는 인자를 
function Counter() {

    const [state, dispatch] = useReducer(reducer, { value: 0 });

    return (
        <div>
            <p>
                현재 카운터 값은 <b>{state.value}</b>
            </p>
            <button onClick={() => dispatch({ type: 'INCREMENT' })}> +1</button>
            <button onClick={() => dispatch({ type: 'DECREMENT' })}> +1</button>
        </div>
    )
}

export default Counter
  • useReducer의 비구조 할당에 의해 설정된 state는 useReducer에서 사용할 상태값(컴포넌트에서)
  • useReducer의 첫번째 파라 미터 ⇒ 리듀서 함수, 두번째 파라미터 ⇒ 해당 리듀서의 기본값을 넣어준다.
  • dispatch는 상태를 변경하는 함수인데 받는 인자(action)에 따라 설정한 상태로 달라진다.
  • type이외에 발생한 상태값을 넣을수 있다. name, value(e.target의) 어차피 switch 문으로 보는건 action의(객체) type(프로퍼티)으로 판단하기 때문이다

useState랑 비슷하지만, 인자에 따라 설정을 바꿀수 있다 생각하자

인풋상태 관리하기

기존에는 인풋이 여러개여서 useState를 여러개 사용했는데

⇒ useReducer을 이용하면 기존 클래스형 컴포넌트에서 했던것 처럼 e.target안에 프로퍼티에 따라 여러개를 사용할 필요가 없다

import { render } from '@testing-library/react';
import React, { useState, useEffect, useReducer } from 'react'

function reducer(state, action) {
    return {
        ...state,
        [action.name]: action.value
    } // 스프레드 문법을 이용해서 기존 stata를 가져오고 , e.target = action으로 줘서 값에 따라 값을 새로 생성한다
}

function Info() {
    const [state, dispatch] = useReducer(reducer, {
        name: '',
        nickName: ''
    }) // 초기 state 값을 설정해주고
    const { name, nickName } = state;
    const onChange = e => {
        dispatch(e.target); // action 값을 dispatch로 보냄
    }
    return (
        <div>
            <div>
                <input
                    name="name" // e.target.name
                    value={name} // e.target.value
                    onChange={onChange}
                />
                <input
                    name="nickName"
                    value={nickName}
                    onChange={onChange}
                />
            </div>
            <div>
                <div>
                    <b>이름:</b> {name}
                </div>
                <div>
                    <b>닉네임:</b> {nickName}
                </div>
            </div>
        </div>
    )
}

export default Info

useMemo

함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다

해당 하는 값의 결과가 useMemo에서 실행되지 않는다면, 결과또한 바뀌지 않는다

이해하기 쉽게 생각한다면

useEffect는 해당 함수의 인자를, 두번째 파라미터로 받으면, 해당 인자가 변경될때만 마운트(랜더링) 된다

useMemo또한 해당 함수의 인자를, 두번째 파라미터로 받으면 useMemo의 리턴값은 해당 함수의 인자가 변경 될때만 변경된다

import React, { useState } from 'react';


const getAverage = numbers => {
    console.log('평균값 계산 중..');
    if (numbers.length === 0) return 0;
    const sum = numbers.reduce((a, b) => a + b);
    return sum / numbers.length;
};



const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState("");

    const onChange = e => {
        setNumber(e.target.value);
    };
    const onInsert = e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber("");
    };

    return (
        <div>
            <input value={number} onChange={onChange} />
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value, index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값:</b> {getAverage(list)}
            </div>
        </div>
    );
};



export default Average;

export default Average

이제 list 배열의 내용이 바뀔 때만 getAverage 함수가 호출됩니다.

useCallback

주로 렌더링 성능을 최적화해야 하는 상황에서 사용된다.

함수또한 랜더링 될때마다 새로 호출 되는데

해당 함수가 만약 함수 내부가 변경되거나 새로 호출 받는게 아니라면

한번만 랜더링하고 계속 사용하는것이 성능에 좋다

함수선언을 useCallback으로 해주면 된다

const onChang = useCallback(e=>{
	setNumber(e.target.value)
},[]);
  • useCallback의 첫번째 파라미터에는 생성하고 싶은 함수
  • useCallback의 두번째에는 배열을 넣으면 된다, 이 배열에는 어떤 값이 바뀌었을때 함수를 새로 생성해야하는지 명시해줘야한다.

useRef

함수형 컴포넌트에서 ref를 쉽게 사용할수 있도록 해준다

useRef를 이용하면, this 처럼 로컬 변수를 사용할수 있게된다.

커스텀 Hooks 만들기

로직을 파일로 따로 만들어 분리 한뒤에

불러와서 쓰면된다.

profile
인터벌로 가득찬

0개의 댓글