모든 React Component는 생명 주기를 가진다. reacte v16.8이후부터 함수형 Component에서도 상태 관리를 할 수 있도록 Hook이 도입되었다.

Life Cycle

마운트

  • 페이지에 컴포넌트가 나타남

업데이트

  • 컴포넌트 정보를 업데이트(리렌더링이 발생함)
      1. props가 바뀔 때
      1. state가 바뀔 때
      1. 부모 component가 리렌더링 될 때
      1. forceUpdate 함수가 실행될 때

언마운트

  • 페이지에서 컴포넌트가 사라짐

♻️ useState

  • 가장 기본적인 상태 관리 Hook.
// 배열의 첫번째 값은 상태값, 두번째 값은 상태 변경을 위한 함수.
// useState(안의 값은 초기 값을 의미한다.
 const [name, setName] = useState('');

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

♻️ useEffect

  • component가 rendering될 때마다 특정 작업을 수행할 수 있도록 함.
  • 기본적으로 렌더링되고 난 직후마다 실행됨.
  useEffect(() => {
    console.log('렌더링완료');
    console.log(name, nickname);
  });

//마운트될 때만 실행하고 싶다면 두 번째 parameter로 빈 배열을 넣으면 됨
  useEffect(() => {
    console.log(name, nickname);
  }, []);

//특정 값만 업데이트될 때만 실행하고 싶을 때는 빈 배열 안에 검사하고 싶은 값을 넣어 주면 됨
  useEffect(() => {
    console.log(name);
  }, [name]);

♻️ useMemo

  • memoization
  • component 내부에서 발생하는 연산을 최적화 할 수 있다.
  • 특정 값이 바뀔 때만 연산을 실행하고 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용한다.
const getAverage = (number) => {
  console.log('계산중');
  if (number.length === 0) return 0;
  const sum = number.reduce((a, b) => a + b);
  return sum / number.length;
};

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

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

  const avg = useMemo(() => getAverage(list), [list]);

  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> {avg} {/* list값이 수정될 때만 계산한다. */}
        {/* <b>평균값</b> {getAverage(list)} */}
      </div>
    </div>
  );
};

♻️ useCallback

  • memoization
  • 렌더링 성능을 최적화하는 상황에 사용
  • 첫 번째 파라미터로는 생성하고 싶은 함수를, 두 번째 파라미터에는 배열을 넣어 줌.
  • 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지를 명시해야 함.
    • 비어 있는 배열이면 컴포넌트가 렌더링될 때 단 한 번만 함수가 생성되며, 배열 내에 요소를 넣으면 해당 요소가 변경될 때만 함수가 생성됨.
  • 함수 내부에서 상태값에 의존해야 할 때는 그 값을 반드시 두 번째 파라미터 안에 포함시켜 주어야 함.
  const onChange = useCallback((e) => {
    setNumber(e.target.value);
  }, []); /* 컴포넌트가 처음 렌더링될때만 생성 */
  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  }, [number, list]); /* number, list값이 업데이트될때만 생성 */
  • 일반 값 재사용 시 : useMemo, 함수 재사용 시 useCallback

♻️ useRef

  • 함수형 component에서 ref를 쉽게 사용할 수 있도록 해 줌.
  • ref안의 값이 바뀌어도 component는 렌더링되지 않음.
const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  const inputE1 = useRef(null);

  const onChange = useCallback((e) => {
    setNumber(e.target.value);
  }, []);
  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
    inputE1.current.focus(); //재랜더링되지 않음.
  }, [number, list]);

✅ 차이점

useRef() VS useMemo()

  • useRef : 클래스로 치면 멤버변수 혹은 dom객체 처럼 특정한 '속성값'을 기억해야 할 때
  • useMemo : 복잡한 함수의 'return값'을 기억해야 할 때

useMemo() VS useCallback()

  • useMemo : '함수 return 값'을 기억
  • useCallback : '함수 reference'를 기억.

♻️ useReducer

  • useState 보다 다양한 상황에 따라 다양한 상태를 다른 값으로 업데이트 하고 싶을 때 사용함.
  • 첫 번째 파라미터로는 리듀서 함수를, 두 번째 파라미터에는 해당 리듀서의 기본값을 넣어 줌.
  • 현재 상태액션값을 전달받아 새로운 상태를 반환하는 함수.
  • 리듀서 함수에서 새로운 값을 만들 때는 반드시 불변성을 지켜 주어야 함
function reducer (state, action) {
      return {...}; //불변성을 지키면서 업데이트한 새로운 상태를 반환해야 함.
  }
}

//액션은 아래와 같은 형태임.
{
  type : 'TYPE'
}
  • 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 장점이 있다.
import React, { useReducer } from 'react';

function reducer (state, action) {
  switch(action.type) {
    case 'INCRMENT':
      return {value:state.value+1};
    case 'DECREMENT':
      return {value:state.value-1};
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, {value:0});
  return (
    <div>
      <p>
        현재 카운터 값은<b>{state.value}</b>입니다
      </p>
      <button onClick={()=>dispatch({type : 'INCRMENT'})}>+1</button>
      <button onClick={()=>dispatch({type : 'DECRMENT'})}>-1</button>
    </div>
  );
};

export default Counter;
  • action은 어떤 값이던 사용 가능하다.
const Info = () => {
  const [state, dispatch] = useReducer(reducer, { name: '', nickname: '' });
  const { name, nickname } = state;
  const onChange = (e) => {
    dispatch(e.target);
  };

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

♻️ custom Hook

//userInput custom Hook
import React, { useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.name]: action.value,
  };
}

export default function useInputs(initalForm) {
  const [state, dispatch] = useReducer(reducer, initalForm);
  const onChange = (e) => {
    dispatch.apply(e.target);
  };
  return [state, onChange];
}

//Info 
import useInputs from './useInputs';

const Info = () => {
  const [state, onChange] = useInputs({
    name: '',
    nickname: '',
  });

  const { name, nickname } = state;
profile
wanna be bright person✨ Front-End developer

0개의 댓글