useRef && useEffect

the Other Object·2023년 2월 26일
0

Ref

  • ref는, JS의 getElenentById()처럼, Component의 어떤 부분을 선택할 수 있게 해주는 방법이다.
  • React에 있는 모든 Component는 Reference Element를 가지고 있어서 어떤 Component에 ref={변수명}을 넣어주면, 해당 Component를 참조하게 된다.

ref가 필요한 상황(DOM에 직접적인 접근이 필요한 상황은 언제인가)

  1. input/textarea 등에 포커스를 해야 할 때
  2. 특정 DOM의 크기를 가져와야 할 때
  3. 특정 DOM에서 스크롤 위치를 가져오거나 설정을 해야 할 때
  4. 외부 라이브러리 (플레이어, 차트, 캐로절 등)를 사용할 때

ref 사용예제

import React, {Component} fome 'react'

class RefSample extends Component {
  
  state = {
    height: 0
  };
  input = null;
  box = null;

  const handleClick = () => {
    this.input.focus();
  };


  render() {
    
    return (
      <div>
      	<input ref={ref => {this.input = ref}} />
		<button onClick={this.handleClick}> Focus Input </button>
		<div ref={ref => {this.box = ref}}>
          <h2>Title</h2>
		  <p>Content</p>
        </div>
		<p>
          <b> height </b> {this.state.height}
        </p>
      </div>
    
    )
  }

}

export default RefSample;

useRef

ㅁ. 특정 DOM을 가리킬 때 사용하는 Hook함수 (focus설정, 특정element의 style변경 등..)
ㅁ. DOM에 접근(이렇게 쓸 경우는 많지않음)
ㅁ. 어떤 가변값을 유지하는데에 편리함

- DOM을 직접 선택해야하는 상황
- 특정요소의 값을 가져오기
- 스크롤바 위치
- 포커스설정
	
    - const 사용자정의이름 = useRef(null)
    - const 사용자정의이름 = useRef()
    - const 사용자정의이름 = useRef(숫자)
    
    	> * <실제돔 ref={사용자정의이름}>
        	
            - 사용자정의이름.current
            - 사용자정의이름.current.xxx명령어
            - .current 프로퍼티에 변경가능한 값을 담고있는 "상자"
  1. 매개변수가 제네릭과 일치하는 useRef
interface MutableRefObject<T> {
  current: T;
}
  1. 초기값에 null이 될 수 있는 유니언타입을 지정하면 RefObject를 반환하는 useRef (: current에 내용을 주입하는 용도로 사용할 수 없다. current가 readonly이기 때문)
interface RefObjext<T> {
  readonly current: T | null;
}
const timeout = useRef(null); //RefObject 반환해서 current가 readonly가 됨

timeout.current = setTimeout(() => {
  startTime.current = new Date().getTime();
}, Math.floor(Math.random() * 1000) + 2000);

// const timeout = useRef<number | null>(null);
// 이걸로 교체해줘야 오류가 안남
  1. 제네릭에 undefined를 넣는 경우. MutableRefObject를 반환한다. 제네릭이 undefined인 경우 사용되며, undefined이므로 매개변수가 아예 없음.

useRef(focus)예제1 (: 3초 뒤에 input창에 포커싱되도록 설정)

import React, {useRef} from 'react';

const App = () => {
  //1.Ref객체 만들기
  const here = useRef();
  //2.focus() DOM API호출
  setTimeout(() => here.current.focus(), 3000);
  return (
   <div>
     <h1> Hello </h1>
     //3.원하는 곳에 ref값으로 설정하기
     <input
       ref={here}
	   placeholder="how are you"
  	 />
   </div>
  );
}

export defaulg App;

* 1. useRef()를 사용해 Ref객체 만들기 : const here = useRef();
* 2. 해당 객체를 활용한 작업설정 : .current.focus()
* 3. 만든 Ref객체를 선택하고싶은 DOM에 ref값으로 설정하기 : ref={here}
  	 => Ref객체의 .current 값은 선택한 DOM을 가리키게 된다.
     +) useRef에 파라미터를 넣어주면 이 값이 .current 의 기본값이 된다.

useRef(Focus)예제2

import React, {useState, useRef} from 'react';
import "./styles.css";

const App = () => {
  const [name, setName] = useState('');
  const [nickName, setNickName] = useState('');
  const hereref = useRef();		//useRef객체생성
  
  const onChangeName = (e) => {
  	setName(e.target.value);
  };
  const onChangeNickName = (e) => {
  	setNickName(e.target.value);
  }
  const onClickReset = () => {
  	setName('');
    setNickName('');
    // 버튼 클릭시 지정한 위치에 focus 되도록
    hereref.current.focus();
  }
  
  rerurn (
    <>
    	// 원하는 위치(DOM)에 ref값을 설정한다.
    	<input
    		value={name}
			onChange={onChangeName}
			hereref={ref} />
        <input
			value={nickName}
			onchange={onChangeNickName} />
        <button onClick={onClickReset}>
          리셋버튼
		</button>
		<div>
			<h3> 결과 </h3>
			<h4>
          		{name}의 별명은 {nickName}입니다.
            </h4>
		</div>
    </>
  );
};

export default App;

useRef(변수관리) 예제

  • useRef 특정 DOM을 선택하는 용도 이외에도 Component 안에서 조회 및 수정이 가능한 변수를 관리하는 용도로도 사용된다. 하지만 useRef를 이용해서 변수를 업데이트 하게 되면,해당 Component가 리렌더링 되지 않기 때문에 리렌더링을 원한다면 callbackRef 를 사용해야한다. 하지만! 굳이 리렌더링이 필요없는 변수를 다룰 때는 useRef를 사용하는 것이 효율적이다.

    useRef를 통해 관리되는 변수가 주로 쓰이는 곳

    • setTimeout, setInterval을 통해 만들어진 id
    • Scroll의 위치
    • 배열에 새 항목이 추가 될 때 필요한 고유 key값
    • 외부 라이브러리를 사용하여 생성된 인스턴스
import React, {useRef} from 'react';
import UserList from './UserList';

const App = () => {
  const users = [		//1.현재 users 라는 배열에 3명의 user가 존재하기 때문에
    {
      id: 1,
      name: 'hjeen'
    },
    {
      id: 2,
      name: 'ijun'
    },
    {
      id: 3,
      name: 'hjij'
    }
  ];
  
  const nextId = useRef(4);		//2.다음에 추가되면 해당 user.id=4 이므로 이렇게 .current 의 기본값을 설정해준다.
  const onCreate = () =>  {
    // 배열에 항목추가 소스
    nextId.current += 1;	//3.그후 배열을 추가하는 부분에 새로 추가되는 배열의 id값을 이렇게 1씩 증가시킨다.
  };
  return (
    <React.Fragment>
      <UserList users={users} />
    </React.Fragment>
  );
};

export default App;

useEffect(함수, [의존값 deps]);

useEffect( () => {
  mount 시 실행할 함수;
  return () => {
    unmount 시 실행할 내용
  }
}, [deps값])
* 기본 사용법
	1. 먼저 `mount` 시 실행할 함수를 작성한다.
    2. 반환 값에는 `unmount`시 실행할 내용을 작성한다. (cleanUp)
	3. `deps`값에 특정 값을 넣으면, 해당 값이 업데이트 될 때마다 useEffect에 작성한 함수가 재실행된다.

* `빈 배열`로라도 두어야 useEffect에 작성한 함수가 처음 mount 될 때만 실행  (생략하면 리렌더링 될 때마다 계속 함수를 불러오게 됨)
* `cleanup`함수 : 해당 effect가 더이상 실행할 필요가 없을 때 청소하는 용도. 더이상 실행할 필요가 없는 경우(1),(2)
				 (1) dependancy(두번째 인자로 넘기는 배열)가 바뀌어서 effect가 달라져야 할  (이전 effect 청소)
				 (2) 해당 Component가 unmount 될 때
** deps 정리
	*** 정리하자면, deps가 []일 떄,
   		1. 컴포넌트가 처음 나타날 때에만 useEffect에 등록한 함수가 호출 됨.
   	    2. return 값은 컴포넌트가 사라질 때 호출 됨
    *** deps에 특정 값을 넣으면 이럴 때 호출이 된다.
  	    1. 컴포넌트가 처음 마운트 될  ( []일 때도 가능 )
		2. 컴포넌트가 언마운트 될  ( []일 때도 가능 )
		3. 지정한 값이 바뀌기 직전에
 	    4. 지정한 (deps에 넣은 값)이 바뀔 
      
    => useEffect 안에서 사용하는 상태나 props가 있다면, deps에 넣어주어야 하는게 규칙이다. 그래야 useEffect 에 등록한 함수가 실행 될 때, 최신 props 나 상태를 가리키기 때문이다.

useEffect 란?

Component가 마운트/un마운트/업데이트 될 때, 할 작업을 선택하도록 하는 Hook함수
=> 기존의 class형에서는 세가지의 각 상태들을 따로 관리해야했는데 useEffect로 한번에 관리 가능
(외부 API를 요청하거나 반복작업/작업예약 등에 쓰인다)

* 세가지의 상태들을 기존의 메서드와 매칭하여 좀 더 알아보자,
  1. `mount` : Component가 처음 화면에서 보여질  (새로고침시) (ComponentDidMount메서드)
  2. `unmount` : Component가 화면에서 사라질  (ComponentWillUnmount메서드)
  3. `update` : 특정 props가 바뀌어 Component가 업데이트 될  (ComponentWillUpdate메서드)

새로운 Hook 만들기 :useClick

  • useClick 이라는 새로운 훅을 만들어서 제목을 클릭할 때마다 콘솔 창에 특정 문구가 나타나도록 해보자.
import React, {useEffect, useRef} from 'react';


const useClick = (onClick) => {
  // 예외처리
  if (typeof onClick !== 'function') {
    return;
  }
  
  const element = useRef();
  
  useEffect( () => {
    // mount 시 실행 (click시, 받아 온 onClick함수 실행)
    if (element.current) {
      element.current.addEventListener('click', onClick);
    }
    return () => {
      if (element.current) {
        element.current.removeEventListener('click', onClcik);
      }
    };
  }, []);
  return element;
}


const App = () => {

  const sayHello = () => {
    console.log('Hello');  
  };
  const title = useClick(sayHello);		//useClick훅에 sayHello함수를 전달
  
  return (
    <div>
      <h1 ref={title}>
		Hello
      </h1>
    </div>
  )
}

0개의 댓글