React 기초공부 - 4

솔다·2023년 2월 10일
0

Ref 사용하기

React에서는 일반적으로 DOM 요소에 id를 달지 않는다.

id를 달아버리면 컴포넌트를 여러번 사용할때 id가 겹치는 문제가 발생할 수 있다.

하지만, React에서는 항상 답을 찾습니다. DOM 내부에 이름을 별개로 달아주는 방법이 있고 그게 ref개념입니다.

ref를 설정해주는 방법은 기본적으로 콜백함수를 작성하는 것이다. 콜백함수 사용예시는 아래와 같다.

<input ref = { (ref) => {this.input = ref}} />

이런식으로 작성하면 된다. 여기서 this.input은 input요소의 DOM을 가리킨다. ref의 이름은 this.legend처럼 마음대로 작성/지정할 수 있다.

createRef를 통한 ref설정

ref를 만드는 또 다른 방법은 리액트에 내장되어 있는 createRef라는 함수를 사용하는 것이다. 이 함수를 사용하는 방법의 예제 코드를 보자.

import React, { Component } from 'react';

classs RefSample extends Component{
  input = React.createRef();
  
  handleFocus = () ={
    this.input.current.focus();
  }
  
  render() {
    return (
      <div>
        <input ref = {this.input} />
      </div>
    );
  }
}

export default RefSample;

예제가 짧은 편이라서 전부 작성해봤는데 이를 보면 간단히 확인할 수 있다. inputReact.createRef();함수를 호출해서 설정해주고 이를 아래에 렌더링 할때 props로 넣어주면 ref가 설정되어 버린다. 다만 주의할 점이 있는데 호출할 때 .current를 넣어야 한다는 것이다.

컴포넌트에 ref달기

내부에서 ref를 달아주던 방법과 동일하게 사용할 수 있다.

<MyComponent
	ref = {(ref) => {this.myComponent=ref}}
/>

컴포넌트간 스크롤 박스 불러오기 예제.

class App extends Componenet {
  render() {
  return (
  	<div>
    	<ScrollBox ref = { (ref) => this.scrollBox=ref}/>
        <button onClick={() => this.scrollBox.scrollToBottom()}>
        맨 밑으로
        </button>
	</div>
   );
  }
}

export default App;

여기서 주의할 점이 있는데, button에서 보면 화살표 함수 문법을 사용해서 아예 새로운 함수를 만들고 그 내부에서 메서드를 실행하는데, 이렇게 안하고 직접적으로 연결하면 버튼을 누를때 렌더링이 안되서(undefined)라고 뜬다. 화살표 함수로 작성하면 버튼을 누를때 렌더링을 해서 에러가 발생하지 않는다.

Map()함수 사용하기

리액트에서는 자바스크립트 내장함수인 map()함수를 이용할 수 있다. 이 사용법을 잘 익혀두어야 배열의 값을 수정해줄 수 있으니, 이를 활용하는 예시를 잘 보자.

...
const[names, setNames] = useState([
	{id: 1, text: '눈사람'},
    {id: 2, text: '얼음'}
  ]);

const onClick = () => {
  const nextNames = names.concat({
    id: nextID,
    text: inputText
  });
}
...

다른 내용들은 좀 생략했다. 집중적으로 볼 부분은 배열 namesconcat()을 사용한 부분이다. array.concat()을 사용하면, 기존의 배열을 바탕으로 새로운 배열을 리턴해준다. 이를 통째로 setNames()에 집어넣어주면 문제는 해결된다.

추가하는 경우 외에 이제 제거하는 경우를 봅시다. 이 경우는 내장함수 filter()를 사용하면 된다.

const numbers = [1,2,3,4,5,6,];
const BiggerThanThree = numbers.filter(number => number>3);
//결과: [4, 5, 6]

filter 함수로 특정 요소를 제외 시킬 수도 있다.

const withoutThree = numbers.filter(number => number !== 3);
//결과: [1,2,4,5,6]

리액트의 라이프사이클

리액트의 모든 컴포넌트에는 라이프사이클이 존재한다. 컴포넌트의 수명은 페이지가 렌더링되기 전인 준비과정에서부터 시작해서 페이지에서 사라질때끝난다.

mount : DOM이 생성되고 웹 브라우저상에 나타나는 것을 mount라고 한다.
update : 업데이트 되는 경우의 수는 4가지 있다. props 변경/state변경/ 부모 컴포먼트 렌더링/ this.forceUpdate로 강제 렌더링시킬때

관련 내용은 중요한데, 이에 관해서는 나중에 별도의 포스팅에서 알아보도록 하자.

Hooks

리액트의 함수형 컴포넌트에서도 상태관리를 할 수 잇는 기능들을 추가한 것들이다. 대표적인 예로는 useState(), useEffect(), 등이 있으며 커스컴 hook도 제작하여 사용할 수 있다.

useState
useState()함수의 파라미터에는 기본값으로 설정하기 원하는 값을 나타낼 수 있는데, const[value, setValue] = useState(0) 이라고 써주면 value의 값이 0으로 설정된다.

useEffect
useEffect()함수는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다. 아래에 사용예시를 작성해보자.

const info = () => {
	const [name, setName] = useState('')
    useEffect(() => {
    	console.log('렌더링이 완료되었습니다.')
        console.log({name})

좀 많이 생략되기는 했지만, 대충 저런 느낌이다.

useEffect()를 부분적으로 사용하고 싶을때는 두번째 파라미터에 배열을 넣어주면된다.

아래에 수정한 예시를 보자.

useEffect(() => {
	console.log(name);
    }, [name]);

이렇게 배열에 name을 넣게되면 이 name의 값이 변경되었는지 확인하고 바뀐 경우에만 log가 찍히게 될 것이다.

언마운트 될때만 실행하고 싶다면, return () 으로 함수를 반환할 수 있는데 이를 cleanup함수라고 부른다. 이 함수는 컴포넌트가 언마운트 될 때 실행된다.

useEffect(() => {
	console.log('effect');
    return () =>{
      console.log('clean up');
      console.log(name);
      };
    }, []);

위의 코드를 보면 여기서도 두번째 인자로 빈 배열을 넣는데, 빈 배열을 넣으면 마운트 될때만 호출이 되고, 언마운트 될때 자동으로 cleanup 함수가 호출되는 구조이다.

아예 두번째 파라미터를 생략해버리면, 리렌더링되면 자동으로 실행하도록 만드는 것이다.

useMemo
useMemo()함수는, 값이 업데이트 되었을때만 수행하는 함수라고 보면 된다. 어떤 리스트의 평균값을 구해야 한다고 했을때, 값이 변하지 않았다면 리렌더링 될 때마다 수행할 필요가 없다.

이런 경우에 useMemo()를 쓰면 된다.

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

이런식으로 작성하면 []배열에 넣어준 녀석의 값에 변동이 있을 때만, 첫번째 파라미터로 들어온 메서드를 수행한다.

useCallback
useMemo()와 상당히 유사한 함수이다. 주로 렌더링 성능을 최적화해야 하는 상황에서 사용한다. 컴포넌트의 렌더링이 자주 발생하거나 컴포넌트의 개수가 많아지면 이 부분을 최적화하면 좋다. 리렌더링이 될 때마다 함수들이 새로 생성되는데, useCallback()함수를 사용하면 새로 생성할 필요가 없다. 아래의 예시를 보자

useCallback(() => {
	console.log('hello world!');
    }, [])

useMemo(() => {
	const fn = () => {
    	console.log('hello world!');
    };
    return fn;
}, [])

두 함수는 완전히 같은 기능을 하는 코드이다. 근데 해당 함수 부분을 새로 생성하지 않고 유지하기 때문에 더 편하게 사용할 수 있다.

useRef
useRef hook은 함수형 컴포넌트에서 ref를 쉽게 사용하도록 해준다. 클래스형 컴포넌트에서 봤던 ref의 효과처럼, useRef()가 동일하게 객체 안의 current값이 실제 엘레먼트를 가리키게 한다.

로컬변수가 필요한 경우에도 편하게 그냥

const id = useRef(1);

위에처럼 넣어버리면 단순하게 만들 수 있다.

Custom Hook

여러 컴포넌트에서 비슷한 기능을 공유할 경우, 커스텀으로 Hook을 제작하여 재 사용할 수 있다. 아래의 코드는 input() 기능을 커스텀으로 제작한 훅의 예시중의 하나이다.

import { useState, useCallback } from 'react';

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    setForm(form => ({ ...form, [name]: value }));
  }, []);
  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;

이런식으로 기본적으로 제공하는 Hook들을 활용해서 우리가 원하는 커스텀 훅을 제작하면 반복되는 항목에 대해서는 편리하게 사용할 수 있다.

0개의 댓글