본문 바로가기
Dev/React

React 정리 (1)

by HenryNoh 2021. 5. 21.

JSX

JSX란 Javascript가 조금 더 확장된 문법이다.

React에서 JSX의 사용은 필수적이지 않다고 말하지만 실질적으로 React를 사용할 때 JSX를 사용한다는 것은 너무나 매력적인 일이다. 특히나 React안에서 javascript를 이용한 UI적인 요소를 관리하고 생성할 때 JSX를 쓴다면 그것은 훨씬 시각적인 일이 되고 편한 코드 생성을 도와줄 것이다.

JSX의 코드 생성은 다음과 같은 형태를 띤다.

const element = <div>Hello! React</div>

위의 코드는 기존의 javascript도 아니며 HTML도 아니다.

또한 다음과 같이 중괄호로 묶어 변수를 사용할 수 도 있다.

const name = 'Henry Noh';
const element = <div>Hello {name}</div>;

또한 JSX는 컴파일이 끝난 후에 Javascript 함수가 호출되며 기존의 Javascript 객체로 인식하게 된다.

따라서 다음과 같은 문법을 사용할 수 있게 된다.

const getGreeting = (user) => {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

실제로 React에서 코드를 작성할 때 component의 속성 값을 변경시켜주기 위하여 우리는 camelCase를 사용하게 되는데 이러한 camelCase를 따르는 규칙 또한 JSX의 문법이다!

const element = <div tabIndex="0"></div>;

 

Hook

React 16.8 버전 이후로 도입된 hook은 더 이상 우리가 LifeCycle을 관리하며 react를 작성할 필요가 없게 만들어 주었다.
그렇다고 LifeCycle이 사라졌다는 것이 아니라 그와 같은 react의 개념을 좀 더 직관적으로 사용할 수 있게 주어지는 API인 것이다.

이제는 더 이상 React에서 조차 class형 컴포넌트가 아닌 functional 컴포넌트를 사용할 것을 추천하기 때문에 class 방식으로 사용하는 것이 필요로 하지 않게 되었다. 하지만 그 뜻이 class 방식을 아예 몰라도 된다는 뜻은 아니다. hook이 나온 이후로 hook을 이용한 functinal 컴포넌트는 이 세상에 존재하는 모든 class형 컴포넌트와 같이 쓸 수 있도록 만들었으며 (class형 컴포넌트 내부에서 사용은 불가능) 실질적으로 새로 작성하는 코드가 아닌 이상 우리는 엄청나게 많은 class형 컴포넌트를 관리하게 될 것이다.

따라서 왜 Hook이 나오게 된 것이며 LifeCycle Method와 같고 다른 점이 무엇인지 파악해야 할 필요성이 있다.

(추후에 작성 예정)


Hook이 나오게 된 이유는 다음과 같다.

  1. LifeCycle을 사용하던 방식의 기존 class형 컴포넌트는 각 method에 필요하지 않은 로직이 섞여있을 때가 있다.
    1. componentDidMount와 componentDidUpdate는 컴포넌트 안에서 데이터를 가져오는 작업을 수행하기 위하여 만든 method이지만 componentDidUpdate에서 이벤트 리스너를 설정하는 것과 같은 관계없는 로직이 포함되기도 한다.
    2. componentWillUnmount에서 cleanup과 같은 로직을 수행하기도 한다.
    3. 상태 관련 로직은 한 컴포넌트를 작은 단위로 분해하기 힘들게 만든다.
  2. Class는 사람과 기계를 헷갈리게 만든다.
    1. React에서 class형 컴포넌트를 사용하기 위해서는 this를 명확하게 알아야만 한다. 하지만 JS의 this는 다른 언어들과는 다르게 그 의미와 용도를 정확하게 파악해야만 잘 사용할 수 있다.

아마 React를 사용하면서 가장 많이 사용하게 될 hook은 2가지 정도가 있을 것이다.

useState

1. 초기값은 1번만! 변경은 언제나 set함수

const [*name*, set*Name*] = useState(*initial property*);

name은 내 마음대로 정할 수 있다. 다만 뒤의 name값을 변경시켜주는 함수는 언제나 setName으로 정해야 한다.
initial property는 컴포넌트의 렌더링이 시작된 순간 단 1번만 사용된다.

2. initial property는 원하는 대로

initial property에 들어가는 값은 변수도 될 수 있고 객체도 될 수 있고 배열도 될 수 있다.

const [count,setCount] = useState(0);
const [name,setName] = usestate('Henry Noh');
const [array,setArray] = useState([{name:'henry'}]);

3. 수정은 다음과 같이

import React, {useState} from 'react';

const App = () => {
  const [count,setCount] = useState(0);
  const [name,setName] = useState('Henry Noh');
  const [obj,setObj] = useState({name:'Henry'});

  //count 변경
  const onChangeCount = () => {
    setCount(1);
  };
  //name 변경
  const onChangeName = () => {
    setName("Michael");
  };
  //객체 변경
  const onChangeObj = (e) => {
    const name = e.target.name;
    setObj({
      ...obj,
      [name] : 'test',
    })
  };

  return (
    <>
      <button onClick = {onChangeCount}>button</button>
      <button onClick = {onChangeName}>button</button>
      <button onClick = {onChangeObj} name="name">button</button>

      <div>{count}</div>
      <div>{name}</div>
      <div>{obj.name}</div>
    </>
  )
};

export default App;

 

useEffect

react 공식 document에 따르면 useEffect를 LifeCycle method의 componentDidMount, componentDidUpdate, componentWillUnmount를 합친 것으로 생각해도 좋다고 말하고 있다.

또한 useEffect 그 자체는 useEffect hook안에 정의된 함수 그 자체를 기억했다가 해당 컴포넌트에 대한 DOM의 업데이트가 이루어진 이후에 그 기능을 수행한다. 즉 해당 컴포넌트가 렌더링이 된 이후에 함수를 실행한다는 뜻이다. 이러한 방식의 동작은 component안에 있는 데이터, 변수를 document 그 자체 내에서 언제든지 자유롭게 사용할 수 있게 된다는 것이다.

import React, {useState, useEffect} from 'react';

const App = () => {
  const [count,setCount] = useState(0);

  //count 변경
  const onChangeCount = () => {
    setCount(1);
  };

  useEffect(()=>{
    document.title = `You Clicked ${count} times`;
  })

  return (
    <>
      <button onClick = {onChangeCount}>button</button>

      <div>{count}</div>
    </>
  )
};

export default App;

이외에도 useContext, useReducer, useCallback, useMemo, useRef와 사용자 정의 Hook을 만들 수 있다.

댓글