본문 바로가기
Progamming/ReactJS

[벨로퍼트] 리액트의 Hooks 완벽 정복하기

by 동그란 혜주 2019. 10. 29.

useState

  • 가장 기본적인 Hook 으로서, 함수형 컴포넌트 에서도 가변적인 상태를 지닐 수 있게 해준다.
const [value, setValue] = useState(0);
  • useState() 함수의 파라미터에 들어가는 값은, 초기값 을 의미하는 것

    • 사용하고자 하는 state 의 기본값을 0 으로 설정

    • useState() 는 배열을 반환

      • 첫 번째 원소, value 는 상태

      • 두 번째 원소, setValue 는 상태를 설정하는 함수

        • setValue 함수에 파라미터를 넣어서 호출 -> 전달받은 파라미터로 value 의 값이 바뀜

useState 여러 번 사용하기

  • useState() 는 하나의 상태 값만 관리 가능

  • 만약, 컴포넌트에서 관리해야하는 상태 값이 여러개라면 useState() 를 여러번 사용

    const [name, setName] = useState('');
    const [nickname, setNickname] = useState('');
p.s
  • onClick 등의 이벤트 핸들러에는 callback 이 파라미터로 들어간다.

    const onChangePlusValue = () => {
            setValue(value + 1);
    };
    
    const onChangeMinusValue = () => {
            setValue(value - 1);
    };
    
    return (
          <button onClick={onChangePlusValue}>+1</button>
            <button onClick={onChangeMinusValue}>-1</button>
    )

useEffect

  • 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행할 수 있는 Hook
  • 기존의 클래스형 컴포넌트의 componentDidMountcomponentDidUpdate 를 합친 형태라고 봐도 무방
  • useEffect() 의 파라미터는 callback
  • 렌더링이 최초 실행되었을 때도 호출됨
    • 최초 렌더링 되었을 때 : Mount 되었을 때
    • componentDidMount 의 역할이 원래 그렇다.
p.s
1. console.log(name, nickname);
2. console.log({ name, nickname });

는 다른 결과를 반환한다.

1. 우혜주 hzoou
2. {name: "우혜주", nickname: "hzoou"}

Mount 될 때만 실행하고 싶을 때

  • 만약 useEffect 에서 설정한 함수가, 컴포넌트가 화면에 최초 렌더링 되었을 때 (즉, Mount 되었을 때) 만 실행되고, 이후에 업데이트 될 경우에는 실행 할 필요가 없도록 설정하고 싶으면 함수의 두번째 인자로 비어있는 배열 (즉, []) 을 넣어줌

    • mount, update 되었을 때 모두 실행

      const completeOnChange = () => {
          console.log('렌더링이 완료되었습니다.');
          console.log({
              name,
              nickname
            });
      };
      
      useEffect(completeOnChange);
    • mount 되었을 때만 실행

      const completeOnChange = () => {
          console.log('마운트 될 때만 실행됩니다.');
          console.log({
              name,
              nickname
          });
      };
      
      useEffect(completeOnChange, []);

특정 값이 Update 될 때만 실행하고 싶을 때

  • 만약 useEffect 에서 설정한 함수가, 특정 값이 변경이 될 때 (즉, Update 되었을 때) 만 실행되고, 다른 값들이 변경되는 경우에는 실행 할 필요가 없도록 설정하고 싶으면 함수의 두번째 인자로 전달되는 배열 안에, 확인하고 싶은 값을 넣어줌

    const completeOnChange = () => {
        console.log('name 값이 업데이트 될 때만 실행됩니다.');
        console.log({
            name,
        });
    };
    
    useEffect(completeOnChange, [ name ]);

뒷정리(cleanup) 하기

  • useEffect 는 기본적으로 렌더링 되고난 직후마다 실행

  • 두 번째 파라미터 배열에 어떤 값을 넣느냐에 따라 실행되는 조건이 결정

  • 만약 컴포넌트가 언마운트 되기 전이나, 업데이트 되기 직전에 어떠한 작업을 수행하고 싶으면, useEffect 에서 뒷정리(cleanup) 함수를 반환해야함

    const completeOnChange = () => {
        console.log('effect');
        console.log({
            name,
            nickname,
        });
        return () => {
            console.log('cleanup');
            console.log({
                name,
                nickname,
            });
        };
    };
    
    useEffect(completeOnChange);
    • 컴포넌트가 보여지는 경우 콘솔 창에 effect
    • 컴포넌트가 사라지는 경우 콘솔 창에 cleanup
      • 렌더링이 될 때마다, cleanup 함수가 실행
      • cleanup 함수가 호출 될 때에는, 업데이트 되기 직전의 값을 반환
p.s
  • 이 부분은 더 공부가 필요하다.

useContext

  • hook 을 사용하면, 함수형 컴포넌트에서 Context 를 보다 더 쉽게 사용 가능

    import React, { createContext, useContext } from 'react';
    
    const blackTheme = createContext('black');
    const redTheme = createContext('red');
    
    const ContextSample = () => {
        const black = useContext(blackTheme);
        const red = useContext(redTheme);
    
        const style = {
            margin: '30px',
            width: '50px',
            height: '50px',
            background: 
        };
        return <div style={style} />;
    };
    
    export default ContextSample;
    • background:black 을 지정한 경우
      • ![image-20191020213905693](/Users/hzoou/Library/Application Support/typora-user-images/image-20191020213905693.png)
    • background:red 를 지정한 경우
      • ![image-20191020213848184](/Users/hzoou/Library/Application Support/typora-user-images/image-20191020213848184.png)
p.s
  • context 개념을 잘 모르겠다.
  • 이 부분도 역시 더 공부가 필요하다.

useReducer

  • useState 보다 더 다양한 상황에 따라, 다양한 상태를 다른 값으로 업데이트 해주고 싶을 때 사용하는 Hook

  • Reducer 는 현재 상태(state)와, 업데이트를 위해 필요한 정보를 담은 액션(action) 값을 전달 받아 새로운 상태를 반환하는 함수

  • Reducer 함수에서 새로운 상태를 만들 때는 꼭 불변성을 지켜주어야 함

    const reducer = (state, action) => {
      return { ... }; // 불변성을 지키면서 업데이트한 새로운 상태를 반환합니다
    }
    • 종종 사용하던 reduce() 와 개념은 비슷한 듯 하다.

카운터 구현하기

const reducer = (state, action) => {
  // action.type 에 따라 다른 작업 수행
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      // 아무것도 해당되지 않을 때 기존 상태 반환
      return state;
  }
}

const 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>
  );
};
  • useReducer 의 첫 번째 인자는 reducer 함수, 두 번째 인자는 해당 reducer 의 초기값
    • state 는 현재 가르키고 있는 상태
      • 처음 지정해준 초기값이 state 가 되는 듯 하다.
    • dispatch 는 액션을 발생시키는 함수
      • dispatch(action) 와 같은 형태로, 함수 안에 파라미터로 액션 값을 넣어주면 리듀서 함수가 호출되는 구조
  • useReducer 을 사용했을 때의 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼내는 것이 가능하다는 점
p.s
  • reducer() 에서 defalut 가 실행되는 것이 가능한가 (?)

인풋 상태 관리하기

  • 앞서, state 가 여러개인 경우에는, useState 를 여러번 사용하는 방법으로 상태관리

    import React, { useReducer } from 'react';
    
    const reducer = (state, action) => {
        return {
            ...state,
            [action.name]: action.value 
            //name이 action.name인 input 태그의 value 를 action.value 로 지정
        };
    };
    
    const Info = () => {
        const [ state, dispatch ] = useReducer(reducer, { name: '우혜주', nickname: 'hzoou' });
        const { name, nickname } = state;
        const onChange = e => {
            dispatch(e.target);
        };
    
        return (
            <div>
                <div>
                    <input name="name" value={name} 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;
    • useReducer 에서의 액션은 그 어떤 값도 가능
      • 위 코드에서는 이벤트 객체가 지니고있는 e.target 값 자체를 액션 값으로 사용
    • 이런 식으로 인풋을 관리하면, 아무리 인풋의 개수가 많아져도 코드를 짧고 깔끔하게 유지 가능

useMemo

  • 함수형 컴포넌트 내부에서 발생하는 연산 최적화 가능
  • 렌더링 하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행
  • 원하는 값이 바뀐 것이 아니라면 이전에 연산했던 결과를 다시 사용하는 방식

리액트의 Hooks 완벽 정복하기

댓글