function reducer (state, action) {
  if (action.type == "INCREMENT")  // action에 따라 분기
      return state + 1;
  else if (action.type == "DECREMENT")
      return state - 1;
  return state;  // 새로운 상태를 리턴
}

function App() {
  const [result, dispatch] = useReducer(reducer, 0); 
  dispatch(result, "INCREMENT");
  return (
    <div>{result}</div> // <div>1</div>
  )
}

useReducer 함수는 useState 대신에 쓸 수 있는 함수이다.

useReducer는 useState의 setState와 다르게 컴포넌트 바깥에 정의할 수 있어서, '컴포넌트 바깥에서 state 업데이트가 가능'은 물론 다른 파일에서도 가능하다는 장점이 있다. 

정확히는 컴포넌트 바깥에 있는 reducer 함수에서 state 업데이트가 가능하다고 말할 수 있다.

useReducer의 사용법은 아래와 같다.

 

const [ state명, 업데이트함수를 호출할 함수명] = useReducer(업데이트함수명, 초기값);

 

state명에는 변수 state의 이름을 넣어준다.

업데이트함수를 호출할 함수명은 이전에 정의해놓은 것을 여기에 넣으라는 게 아니다. useReducer의 파라미터로 업데이트할 함수를 적어주면 리턴값으로 그 업데이트함수를 호출할 함수를 리턴해주는데 이것의 이름을 새로 지어 넣는다.

useReducer의 파라미터로는 '업데이트할 함수명'과 '초기값'을 넣는다.

 

초기값이 0인 상태 a가 있는데 이것을 업데이트할 함수명이 reducer라고 치면 아래와 같이 된다.

const [a, callReducer] = useReducer(reducer, 0);

 

그리고 이렇게 정의한 callReducer는 상태를 업데이트할 부분에서 callReducer(액션객체)와 같이 사용한다.

액션객체는 무엇일까? 내가 내린 정의로는 자기가 if문에 넣을 플래그 등을 담은 커스텀 객체이다.

type이 INCREMENT면 +1을 하고 싶으면 이 액션객체에 type을 INCREMENT라고 명시해서 보내면 되는데

callReducer({type: 'INCREMENT'}) 와 같이 사용하면 된다.

 

그리고 callReducer로 호출된 reducer 함수에서는 새로운 상태를 반환하도록 하게 하면 된다.

 

 

'프론트엔드 > React' 카테고리의 다른 글

React.memo  (0) 2021.09.12
useCallback  (0) 2021.09.06
useMemo  (0) 2021.09.06
useEffect  (0) 2021.09.03
useRef  (0) 2021.09.03

useRef컴포넌트가 가지고 있는 어떤 변수의 값바뀌어도 컴포넌트가 리렌더링되지 않게 하도록 하기 위해 사용한다.

useMemo는 단순히 값이 바뀌지 않았을 때는 을 재사용하기 위해 사용하는 것이다. 컴포넌트의 변수든, 함수의 변수든...

useCallback은 props가 바뀌지 않았을 때는 기존의 함수를 재사용할 때 사용하는 것이다.

React.memo는? props가 바뀌지 않았을 때 컴포넌트의 재사용을 위한 것이다. 즉, 리렌더링을 막는 것이다.

 

React.memo에 대해서는 나중에 포스팅하겠다...

 

 

'프론트엔드 > React' 카테고리의 다른 글

useReducer  (0) 2021.09.14
useCallback  (0) 2021.09.06
useMemo  (0) 2021.09.06
useEffect  (0) 2021.09.03
useRef  (0) 2021.09.03

지난번에 포스팅했던 useMemo이 값의 재사용을 위한 것이라면 useCallback은 함수의 재사용을 위한 Hook 함수이다.

지난번에 사용했던 회원가입 App 컴포넌트를 가져왔다.

import React, { useState } from 'react';
 
function countUsers (users) {
  console.log("회원 수를 세는 중...");
  return users.length;
}
 
function App() {
  const [users, setUsers] = useState([]);
 
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
 
  const { username, email } = inputs;
  const onCreate = () => {
    setUsers([
      ...users,
      {
        username: username,
        email: email
      }
    ]);
  }
 
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  }
 
  const count = countUsers(users);
 
  return (
    <div>
      <input name='username' onChange={onChange} value={username} placeholder='이름'></input>
      <input name='email' onChange={onChange} value={email} placeholder='이메일'></input>
      <button onClick={onCreate}>등록</button>
      <div>
        {
          users.map(user => <div>{user.username} ({user.email})</div>)
        }
      </div>
      <div>전체 회원 수: {count}</div>
    </div>
  )
}
export default App;

 

여기서 onCreate, onChange 함수는 컴포넌트가 리렌더링될 때마다 새로 만들어진다.

39, 40번째줄에 있는 username과 email을 입력하는 input은 키를 하나 입력할 때마다 App이 리렌더링되는데,

그 때마다 App 컴포넌트의 내부 함수인 onCreate와 onChange 함수가 계속 새로 만들어지는 것이다.

이들을 새로 만들지 않고 재사용하기 위해서 useCallback 함수를 사용할 수 있다.

사용법 역시 useMemo와 비슷하다.

 

useCallback(함수, [함수를 새로 만들지 말지 결정할 변수들])

17번째줄에 있는 onCreate 함수에 적용해보면 다음과 같다.

  const onCreate = useCallback(() => {
    setUsers([
      ...users,
      {
        username: username,
        email: email
      }
    ]);
  }, [users, username, email]);

 

onCreate 함수 내에서 사용하고 있는 '상태'들은 users, username, email이다.

만약 이 값들이 변했는데도 성능을 최적화하겠다고 두번째 파라미터에 이 상태들을 넣지 않으면 onCreate 함수가 실행될 때 현재 users가 아닌 초기값을 사용하는 등 예상치 못한 결과를 낳을 수 있다.

이런 일을 방지하기 위해 useCallback의 두번째 파라미터에는 '이 상태들이 변하면 함수를 새로 만들어주세요'하고 dependencies들을 넣어주어야 한다.

'프론트엔드 > React' 카테고리의 다른 글

useReducer  (0) 2021.09.14
React.memo  (0) 2021.09.12
useMemo  (0) 2021.09.06
useEffect  (0) 2021.09.03
useRef  (0) 2021.09.03

useMemo는 성능 최적화를 위해 연산된 값을 재사용할 때 사용한다.

사용자이름, 이메일을 넣으면 회원가입이 가능한 App 컴포넌트가 있다.

그리고 현재 회원가입이 완료된 회원 수를 세는 countUsers 함수가 있다.

import React, { useState } from 'react';

function countUsers (users) {
  console.log("회원 수를 세는 중...");
  return users.length;
}

function App() {
  const [users, setUsers] = useState([]);

  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });

  const { username, email } = inputs;
  const onCreate = () => {
    setUsers([
      ...users,
      {
        username: username,
        email: email
      }
    ]);
  }

  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  }

  const count = countUsers(users);

  return (
    <div>
      <input name='username' onChange={onChange} value={username} placeholder='이름'></input>
      <input name='email' onChange={onChange} value={email} placeholder='이메일'></input>
      <button onClick={onCreate}>등록</button>
      <div>
        {
          users.map(user => <div>{user.username} ({user.email})</div>)
        }
      </div>
      <div>전체 회원 수: {count}</div>
    </div>
  )
}
export default App;

 

초기상태

 

회원 2명이 가입한 상태

 

위 스크린샷을 보면 아무 문제가 없어보인다.

하지만 input에 '이공원' 등 입력하기 위해서 키보드를 누를 때마다 countUsers 함수가 실행되는 문제가 발생하고 있다.

countUsers 함수가 매번 실행되는 것은 console.log("회원 수를 세는 중...")을 통해서 알 수 있다.

 

그 이유는 35번째줄 const count = countUsers(user); 때문이다.

html <input>에 입력이 들어올 때마다 App 컴포넌트의 상태인 inputs가 바뀌므로 App이 매번 리렌더링되고,

그 때마다 countUsers가 재호출되는 것이다.

 

이러한 불필요한 함수 호출을 줄여 성능을 최적화하기 위해서는 useMemo라는 Hook 함수를 사용할 수 있다.

useMemo는 값을 저장해서 이 값이 이전과 달라지지 않았다면 함수를 호출하지 않고 이전 값을 재사용해서 성능을 최적화한다.

 

사용법은 useMemo(값을 새로 연산하기 위해 호출할 함수, [함수를 호출할지 말지 결정하는 변수이름]) 이다.

위 App 컴포넌트에서 함수를 호출할지 말지 정하는 변수이름은 users이다. 그리고 값을 새로 연산하기 위해 호출할 함수는 countUsers이다. 

여기서 참고로 '컴포넌트에서 함수를 호출할지 말지 정하는 변수'는 deps라고 불린다. dependencies...

const count = useMemo(() => countUsers(users), [users])를 35번째줄에 대신 넣으면

input에 입력을 하는 등 실제 회원수가 변하지 않았는데도 count를 계산하기 위해 countUsers를 매번 호출하는 일이 없어진다.

'프론트엔드 > React' 카테고리의 다른 글

useReducer  (0) 2021.09.14
React.memo  (0) 2021.09.12
useCallback  (0) 2021.09.06
useEffect  (0) 2021.09.03
useRef  (0) 2021.09.03

useEffect를 사용하면 컴포넌트가 화면에 나타날 때 & 사라질 때,

props가 업데이트 될 때 & 업데이트 되기 전에 할 행위들을 정해줄 수 있다.

useEffect를 사용하기 위해서 코드 맨 윗줄에 import React, { useEffect } from 'react';를 추가해야 한다.

 

useEffect의 첫번째 파라미터에는 화면에 나타날 때 실행할 함수를 넣어주고,

그 함수의 리턴 값으로는 화면에 사라질 때 실행될 함수를 넣어준다(생략가능). 두번째 파라미터는 []로 비워준다.

아래와 같이 작성하면 User 컴포넌트가 화면에서 사라질 때마다 '컴포넌트가 화면에 나타남'이 콘솔에 출력되고,

컴포넌트가 화면에서 사라질 때마다 '컴포넌트가 화면에서 사라짐'이 콘솔에 출력된다.

 

function User (props) {

  const { name, email } = props;

  useEffect( () => {

    console.log("컴포넌트가 화면에 나타남");

    return () => {

      console.log("컴포넌트가 화면에서 사라짐");

    }

  }, []);

  return (

    <div>

      <b>{name}</b> ({email})

    </div>

  )

}

 

컴포넌트가 화면에서 나타나고 사라질 때 실행되는 것이 아니라

props가 업데이트될 때와 업데이트 되기 전에 할 행위들을 지정하고 싶으면

useEffect의 첫번째 파라미터로 props가 업데이트 되고 나서 할 함수를 작성하고,

그 함수의 리턴 값으로는 props가 업데이트 되기 전에 할 함수를 작성한다.

그리고 두번째 파라미터로 그 props의 이름을 넣어준다.

 

아래와 같이 작성하면 User 컴포넌트가 처음 화면에 나타날 때 'name 값이 설정됨'이 출력된다. 그리고

User의 props인 name이 변경될 때마다 먼저 'name 값이 설정되기 전에 할 일'이 출력되고,

'name 값이 설정됨'이 출력된다.

 

function User (props) {

  const { name, email } = props;

  useEffect( () => {

    console.log("name 값이 설정됨");

    return () => {

      console.log("name 값이 설정되기 전 할 일");

    }

  }, [name]);  // <- 이 props가 업데이트될 때마다 useEffect가 발동된다

  return (

    <div>

      <b>{name}</b> ({email})

    </div>

  )

}

 

 

'프론트엔드 > React' 카테고리의 다른 글

useReducer  (0) 2021.09.14
React.memo  (0) 2021.09.12
useCallback  (0) 2021.09.06
useMemo  (0) 2021.09.06
useRef  (0) 2021.09.03

useRef는 두 가지 방식으로 쓰인다.

1) 특정 DOM을 선택할 때

2) 값이 바뀌어도 컴포넌트를 리렌더링 할 필요 없을 때, 그러한 상태들을 생성

useRef를 사용하려면 코드 맨 윗줄에 import React, { useRef } from 'react' ; 를 추가해야 한다.

 

1) 특정 DOM을 선택할 때.

Counter라는 함수 컴포넌트가 있고 이 컴포넌트는 특정 div의 text를 가져와서 1씩 증가시키는 역할이다.

아래와 같이 컴포넌트 안에 useRef를 이용해 변수를 생성하고,

function Counter (props) {

  const count = useRef(); 

}

 

선택을 원하는 DOM 안에서는 ref={변수명} 을 추가해준다.

<div ref={count}>0</div>

 

값의 변경을 원하는 함수 안에서는 변수명.current 다음에 원하는 행위를 작성한다.

function Counter (props) {

  const counter = useRef();

 

  const onIncrease = () => {

    count.current.innerText = parseInt(count.current.innerText) + 1;

  }

}

 

 

2) 값이 바뀌어도 컴포넌트를 리렌더링 할 필요 없을 때

useState로 상태 값 A가 생성되면 이 A가 바뀔 때마다 컴포넌트가 리렌더링되는데,

굳이 상태가 바뀌어도 컴포넌트를 리렌더링할 필요 없을 때가 있을 것이다.

그럴 때 사용하는 것이 useRef이다. 

count 값이 바뀌어도 그냥 내부에 가지고 있을 뿐 컴포넌트를 리렌더링 할 필요는 없다고 해보자. (사용자에게 보여줄 필요가 없을 때?)

 

function Counter (props) {

  const count = useRef(0);  // 0은 초기값

 

  const onCreate = () => {

    const.current += 1;
  }

}

 

1)과 마찬가지로 변수명.current 에 값을 작성해주면 된다.

'프론트엔드 > React' 카테고리의 다른 글

useReducer  (0) 2021.09.14
React.memo  (0) 2021.09.12
useCallback  (0) 2021.09.06
useMemo  (0) 2021.09.06
useEffect  (0) 2021.09.03

+ Recent posts