useMemo

gyomni·2022년 2월 24일
0

React

목록 보기
4/9
post-thumbnail

useMemo 를 사용하여 연산한 값 재사용하기

  • 성능 최적화를 위하여 이 전에 연산된 값을 useMemo라는 Hook 을 사용하여 재사용.

  • 성능을 최적화 해야 하는 상황에서 사용.

  • 특정 값이 바꼈을때만 특정 함수 실행해서 연산을 하도록 처리.

  • 원하는 값이 바뀌지 않았다면, 리렌더링할 때 예전에 만들어 놨던 값을 재사용할 수 있음.

  • Memo 는 "memoized" 를 의미하는데, 이는, 이전에 계산 한 값을 재사용한다는 의미를 가지고 있다.

useMemo 불러오기

import React,{useMemo} from 'react'; 

countActiveUsers 라는 함수 생성 -> active 값이 true 인 사용자 수를 세어서 화면에 렌더링

App.js

import React,{useRef, useState, useMemo} from 'react'; 
import CreateUser from './CreateUser';
import UserList from './UserList';

function countActiveUsers(users){
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user=>user.active).length;
}

function App(){

  // 상태 설정
  const [inputs, setInputs] =useState({
    username:'',
    email:'',
  });

  const {username, email} = inputs; // username, email을 imputs에서 추출.

  const onChange = e =>{
    const {name, value}=e.target;

    setInputs({
      ...inputs,
      [name]:value // name값을 value로 덮어씌우겠다.name이 가리기고 있는것 : ( CreateUser.js의 ) name or username . 
                   // [name]이 name이면 name을 바꾸고, [name]이 username이면 username을 바꾼다. 
    });
  };


  // 배열을 컨포넌트 상태로서 관리.  users, setusers함수를 useState로 감싸주기. ->users를 return()에서 사용할 수 있게 됨.
  const [users, setUsers] = useState([ 
    {
        id:1,
        username: 'gyomni',
        email: 'hi1@gmail.com',
        active:true,
    },
    {
        id:2,
        username: 'joy',
        email: 'hi2@gmail.com',
        active:false,
    },
    {
        id:3,
        username: 'zoe',
        email: 'hi3@gmail.com',
        active:false,
    }
    ]);

    // 배열의 불변성을 지키면서 새로운 항목을 추가하는 방법 : spread 연산자(...), concat
const nextId = useRef(4); // nextId를 useRef로 관리해주는 이유는 (4)값이 바뀐다고 해서 컴포넌트가 리랜더링 뒬 필요가 없기 때문.
                          // 컴포넌트가 리렌더링 되도 값은 기억됨. 즉 값이 바뀐다고 해서 컴포넌트가 리렌더링 되지 않음!

const onCreate=()=>{
  const user={
    id:nextId.current,
    username,
    email,
  };
  setUsers([...users, user]); // 혹은 users.concat(user)로 배열 붙여주기, user에 값을 추가한다고 user.push(user); 이렇게 하면 업데이트 안됨.( slice x, sort x )-> 꼭 사용해야 한다면 배열 복사 후 사용.
                              // 기존의 배열 바꾸지 않고, 새로운 배열을 만들어서 거기에 변화를 주는 방식으로 구현.
                              // 객체와 마찬가지로 배열에서도 ...사용!
                              // setUsers([...users.concat(user)); -> concat사용해도됨!
  setInputs({
    username:'',
    email:''

  });
  nextId.current+=1; // 여기서 리렌더링 되도 컴포넌트 값이 바뀌진 않음.
};

const onRemove = id =>{
  //  각 아이템들을 파라미터에서 받아온 아이템과 비교한다 -> 만족하는 경우에 새로운 배열만들어서 넣음. 아니면 안넣음.  -> setUsers배열 업데이트.
  setUsers(users.filter(user=>user.id !==id)); // 제거할 때 filter사용 (불변성) 값이 false가 되면 해당 배열에서 제외되면서 삭제됨.
};

const onToggle =id =>{ 

  // onRemove처럼 id값을 파라미터로 가져오기. users에 있는 특정 id를 선택해서 active 값을 반전시키기. 
  setUsers(users.map( // 불변성을 지키면서 배열 업데이트 할때 map 함수를 사용해서 구현할 수 있음.
    // map함수는 특정 배열을 새로운 형태를 가진 형태로 변환시켜줄 때 사용하지만, 배열에 있는 특정 아이템만 업데이트 할 때에도 map사용가능. 

    user=>user.id ===id
    ?{ ...user, active: !user.active} // ...user -> user객체를 업데이트 할 것인데, 그 객체를 업데이트 할 때에도 불변성 지켜줘야 함. // 특정 객체를 업데이트 할 때 ...user로 기존의 user을 수정하는게 아니라, 새로운 객체를 만들어서 기존의 user가 들어있던 값을 넣어주고 특정 값을 덮어줌. 
    : user
  ));
}
  const count =useMemo(()=>countActiveUsers(users),[users]);


  return (  
  <>
  <CreateUser 
    username={username} 
    email={email} 
    onChange={onChange} 
    onCreate={onCreate} 
    />
  <UserList users={users} onRemove={onRemove} onToggle={onToggle}/>
  <div>활성 사용자 수 : {count}</div>
  </>
  )
  }

export default App;

CreateUser.js

import React from "react";

function CreateUser({username, email, onChange, onCreate}){ // onChange: input 값이 바뀌게 될 때 호출할 이벤트, onCreate : 버튼 눌렀을 때 새로운 항목 등록해주는 함수
    return(
        <div>
            <input 
            name="username" 
            placeholder="계정명" 
            onChange={onChange} 
            value={username}
            />
            <input
            name="email" 
            placeholder="이메일" 
            onChange={onChange} 
            value={email}
            />
            <button onClick={onCreate}>등록</button>

        </div>
    )
    
}

export default CreateUser;

UserList.js

import React, { useEffect } from "react";

function User({user, onRemove,onToggle}){ // User라는 컴포넌트 만들어줌.
    const {username, email, id, active} =user; // 밑에서 user. 쓰기 번거로워서  미리 추출해서 쓰기
    
    useEffect(()=>{ // 특정 값이 업데이트되고 난 직후에 실행이 됨.
        console.log('user값이 설정됨');
        console.log(user);
        return()=>{
            console.log('user 값이 바뀌기전');
            console.log(user);

        }
    },[user]); // useEffect의 뎁스 배열에다가 어떤 값을 넣게 된다면 해당 값이 바뀔 때 마다 우리가 등록한 함수 호출. 해당 값이 바뀌기 직전에는 우리가 위에 설정한 clear함수 호출
// useEffect를 사용할 때는 첫번째 파라미터는 함수, 두번째 파라미터는 [] (뎁스라는 배열), return으로 특정함수 반환하게 되면 뒷정리 함수(cleanup)여서 업데이트 바로되기 직전에 호출.
// 조회하고 있는 값 있으면 []에 넣어주기.
    return(
        <div>
            <b 
            style={{
                color: active ?'green':'black',
                cursor:'pointer',
            }}
            onClick={()=>onToggle(id)}
            >
            {username} 
            </b>
            &nbsp;
            <span>({email})</span>      {/*위에서 user추출했기때문에 user.email이 아닌 email로 썼음.*/}
            <button onClick={()=>onRemove(id)}>삭제</button>  {/*파라미터를 넣어주고 싶기 때문에 새로운 함수 만들기. 함수를 호출하는게 아니라 함수를 만들어서 넣어줘야함. onRemove(user.id) 에서 user쓰기 번거로우면 line4처럼 추출하면 그냥 id로 쓰면됨 */}
                    {/* ㄴ> 함수로 만들어주는 것이 아니라(함수를 호출하는 함수를 만들어줬음), onClick={onRemove(id)} 이렇게 하면 : 렌더링 되는 순간 onRemove(id)가 호출되버림. 그래서 컴포넌트가 실행되자마자 다 사라짐. */}
        </div>
    );

}
function UserList({users, onRemove,onToggle}){ // users배열을 props로 받아오기
    

    return(
        <div>
            {
                users.map(
                    (user)=>(
                    <User 
                        user={user} 
                        key ={user.id}
                        onRemove={onRemove}
                        onToggle={onToggle}
                        />) 
                )
            }

        </div>
    );
}

export default UserList;

코드 파헤치기

📍

function countActiveUsers(users){
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user=>user.active).length;
}
const count =useMemo(()=>countActiveUsers(users),[users]);
  • 첫번째 파라미터: 어떻게 연산할지를 정의하는 함수 넣기.
  • 두번째 파라미터: Deps 배열 넣기
    -> 배열 안에 넣은 내용이 바뀐다면 : 우리가 등록한 함수를 호출해서 값을 연산.
    -> 내용이 바뀌지 않았다면 : 이전에 연산한 값을 재사용함.
  • Users가 호출 될 때만 호출이 되고,
    그렇지 않으면 이전값을 Deps 안의 값이 바뀌여야만 값( users )을 새로 연산해줌.

학습 : 벨로퍼트와 함께 하는 모던 리엑트

profile
Front-end developer 👩‍💻✍

0개의 댓글