react hooks(useReducer, useImperativeHandle, useLayoutEffect)

katanazero·2020년 8월 18일
0

react

목록 보기
6/15
post-thumbnail

useReducer

  • 컴포넌트 상태값을 리덕스의 리듀서처럼 관리
  • useState 를 사용해도 좋으나, 개인적으로 깊이가 있는 자식 컴포넌트에게 상태값 변경을 하는 함수를 전달 시, useReducer 로 상태를 관리하면서 dispatch 로 통일화 시키면 좋은거 같다는 생각을 했다.
import React, {useReducer, useState, useRef} from 'react';
import ChildComponent from "./components/ChildComponent";
import PublicChildComponent from "./components/PublicChildComponent";
import UseLayoutEffectComponent from "./components/UseLayoutEffectComponent";


const INITIAL_STATE = {
    name: 'default',
    age: 0
};

function reducer(state, action) {
    switch (action.type) {
        case 'SET_NAME' :
            return {
                ...state,
                name: action.name
            };
        case 'SET_AGE' :
            return {
                ...state,
                age: action.age
            };
        default :
            return {
                ...state
            };
    }
}

const SET_NAME = 'SET_NAME';
const SET_AGE = 'SET_AGE';


// context API 생성
export const AppContext = React.createContext(null);

export default function App() {

  const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
  const publicChildComponentRef = useRef();

    return (
        <div style={{border: '1px dotted pink', padding: '4px'}}>
            <p>
                useReducer
            </p>
            <p>
                my name is {state.name}
            </p>
            <p>
                my age is {state.age}
            </p>
            <div>
                <button onClick={()=>dispatch({type : SET_NAME, name : '홍길동'})}>이름 변경</button>
                <button onClick={()=>dispatch({type : SET_AGE, age : 20})}>나이 변경</button>
            </div>
            <hr/>
            <div>
                <p>
                    context API 와 useReducer 훅을 이용하면, 상위 컴포넌트에서 깊은 하위컴포넌트에게 이벤트 처리 함수를 쉽게 전달이 가능<br/>
                    dispatch 함수는 값이 변하지 않는 특징이 있음(useCallback 훅을 이용하여 기억할 필요도 없음)
                </p>
                <AppContext.Provider value={dispatch}>
                    <ChildComponent/>
                </AppContext.Provider>
            </div>
            <div style={{border : '1px dotted red', padding : '4px'}}>
                <p>
                    useImperativeHandle
                </p>
                <PublicChildComponent publicChildComponentRef={publicChildComponentRef}/>
                <button onClick={() => publicChildComponentRef.current && publicChildComponentRef.current.addNumberValue()}>숫자 값 증가시키기</button>
                <button onClick={() => publicChildComponentRef.current && publicChildComponentRef.current.setNumberValue(0)}>숫자 값 초기화</button>
            </div>
            <div style={{border : '1px dotted blue', padding : '4px'}}>
                <UseLayoutEffectComponent/>
            </div>
        </div>
    );
}
  • useReducr 훅은 첫번째 인자는 reducer 함수이며, 두번째 인자는 초기 상태값
  • 리덕스의 dispach 함수와 같은 방식으로 사용하여 state 를 업데이트 해준다.
  • context API 와 userReducer 훅을 잘 이용하면, 이벤트 처리 함수를 깊은 자식 컴포넌트에게 쉽게 전달이 가능(dispatch 함수는 값이 변하지 않는 특징이 있어서 불필요한 렌더링이 발생하지 않음)

useImperativeHandle

  • 부모 컴포넌트에서 자식 컴포넌트에 접근가능한 함수를 정의할때 사용
import React,{useState, useImperativeHandle, useRef} from "react";

// ref 속성명을 사용하고 싶다면, React.forwardRef() 함수 사용하기
export default function PublicChildComponent({publicChildComponentRef}) {
    // App 컴포넌트에서 에서 ref 를 넘기지 않았다면 null 로 넘어와 에러가 일어나게 된다.

    const [number, setNumber] = useState(0);

    // 마치 함수형 컴포넌트를 클래스처럼 public / private 하게 사용가능하게 해준다.
    // 1번째 인자 : ref
    // 2번째 인자 : 외부로 공개할 함수(ref.current 로 접근)
    useImperativeHandle(publicChildComponentRef, () => {
        return {
            setNumberValue : (targetNumber) => setNumber(targetNumber),
            addNumberValue : () => setNumber(number + 1),
        }
    });

    return (
        <div>
            number is {number}
        </div>
    )
}
  • useImperativeHandle 훅은 첫번째 인자로 ref 객체를 받고, 두번째 인자로 부모 컴포넌트에서 접근가능한 함수를 객체의 메서드 형태로 작성한다.
  • 부모 컴포넌트에서는 refObject.current.메서드명 으로 접근
  • 자식 컴포넌트에 메서드를 외부에 보낼수 있으며, 내부에 공개하고 싶지 않은 메서드는 private 하게 관리 가능

useLayoutEffect

  • useEffect 훅처럼 부수효과를 처리하는 훅. 다른점은, useEffect 훅은 비동기 / useLayoutEffect 훅은 동기로 처리
    렌더링 후, DOM 요소를 조작할때 useLayoutEffect 훅을 사용하는것이 적합하지만 많은 연산처리를 하는경우 성능이슈가 있을수 있으니 주의해서 사용해야 한다.
import React,{useEffect, useLayoutEffect}from "react";

export default function UseLayoutEffectComponent() {

    // rendering 결과가 DOM 에 반영된 후 비동기로 호출
    // 일단 화면을 보여주고 실행
    useEffect(() => {
        // do side effects
        console.log(`useEffect hook..`);
        return () => {

        }
    }, []);

    // rendering 후, DOM 에 반영되기 전에 동기로 호출
    // 여기서 연산을 많이하면, 동기로 호출이 되기때문에 브라우저가 먹통이 되는 경우가 있으니 주의
    // rendering 후, 변화과 완료된 DOM 을 보여주기 때문에 DOM 조작시 오히려 더 적합
    // 모든 처리를 다 하고, 화면을 보여줌
    useLayoutEffect(() => {
        // do side effects
        console.log(`useLayoutEffect hook..`);
        return () => {

        }
    }, []);

    console.log(`UseLayoutEffectComponent render..`);

    return (
        <div>
            <p>
                useLayoutEffect
            </p>
            <p>
                콘솔창을 확인하면 <br/>
                UseLayoutEffectComponent render..<br/>
                useLayoutEffect hook....<br/>
                useEffect hook..<br/>
            </p>
        </div>
    )
}
profile
developer life started : 2016.06.07 ~ 흔한 Front-end 개발자

0개의 댓글