2 minute read

오랜만에 어렵고도 재밌지만 봐도봐도 모르겠는 리액트 학습시간이 돌아왔다.

우선 리액트의 특징을 짚어보며 어떤부분을 학습할 것인지 알아보자.

리액트의 특징

리액트는 페이지 단위로 제작하는것이 아닌, 컴포넌트 단위로 제작한다.

어떤 앱이 있고, 이 각각의 역할을 하는 컴포넌트들이 있다.

그 컴포넌트들이 조립되어 앱의 한 페이지를 만든다.

때문에 리액트로 앱을 제작할 때는 컴포넌트를 먼저 작성한 뒤 페이지를 만드는

상향식(Bottom-up)으로 제작한다.

하지만 데이터는 위에서 아래로 흐르는 하향식(Top-down)이며,

Props를 이용해 부모 컴포넌트로부터 데이터를 인자처럼 받아와 사용할 수 있다.

이때, 부모 컴포넌트로부터 받은 데이트를 자식컴포넌트는 어디서 온건지, 하드 코딩을 한건지,

무엇을 어쨌는지 전혀 알 수 없다. 단지 데이터만 받을 수 있는 것이다.

이를 단방향 데이터 흐름(one-way data flow) 라고 한다. 리액트에서 가장 중요한 특징이다.

하지만, 자식 컴포넌트에서 이벤트가 발생했을 때, 자식 컴포넌트가 부모 컴포넌트를 변경시키는

역방향 데이터 흐름이 일어날 때가 있다.

예를 들어, 새로운 트위터를 작성하는 컴포넌트(자식)를 이용해 내용을 추가하려면,

전체 트위터 목록(부모)에 데이터를 추가해야 한다.

이는 부모 컴포넌트에서 자식 컴포넌트로 데이터가 흐르는 단방향 데이터 흐름과는 상반되는 일이다.

때문에, 상태를 변경시키는 함수 자체를 자식 컴포넌트에 Props로 전달해서 자식 컴포넌트가 그 함수를 실행하게 한다.

이를 State 끌어올리기, Lifting State Up이라고 부른다.

function ParentComponent() {
  const [value, setValue] = useState('기본 상태');

const handleChangeValue = () {
  setValue('바뀌는 녀석');
};

// 위와 같이 부모 컴포넌트에 상태를 바꾸는 함수 handleChangeValue가 있다.

  return (
    <div>
      <div>{value} 입니다</div>
      <ChildComponent handleButtonClick = {handleChangeValue} />
    </div>
  );
}

// ParentComponent에서 ChildComponent를 불러오면서 Props를 handleButtonClick로
// 상태를 바꾸는 함수 handleChangeValue 자체를 설정해줬다.

function ChildComponent({ handleButtonClick }) {
  const handleClick = () => {
    handleButtonClick()
  }

  return (
    <button onClick={handleClick}>Value 변경</button>
  )
}

// ChildComponent의 button이 클릭되면, handleClick 함수가 실행되고,
// props로 전달받은 handleButtonClick(부모 컴포넌트에서 전달받음 handleChangeValue함수 자체)
// 가 실행되어 결과적으로 부모 컴포넌트에서 자식 컴포넌트로 데이터가 흐르는 단방향 데이터 흐름이면서
//  자식 컴포넌트가 부모 컴포넌트를 변경시키는 역방향 흐름이 완성됐다.

Side Effect

함수 내에서 어떤 Effect가 함수 외부에 영향을 끼칠 경우 Side Effect가 있다고 표현한다.

let tset1 = 'Hello';

function test2() {
  test1 = 'World';
}

test2();

// test2 함수는 전역변수 test1을 수정한다.
// 이때, test2는 Side Effect를 발생시키는 것이다.

Pure Function (순수 함수)

오직 함수의 입력만이 함수의 결과에 영향을 주는 함수이다.

함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치면 순수 함수라고 부르지 않는다.

또한, 입력으로 전달된 값을 수정하지 않는다.

어떠한 인자가 전달 됐을때, 리턴값이 예측이 된다.

때문에 Math.random() 함수처럼 리턴값을 예측할 수 없는 함수는 순수 함수가 아니다.

function upper(str) {
  return str.toUpperCase();
}

upper('hello') // 'HELLO'
str // 'hello'

// toUpperCase()는 원본을 수정하지 않는다.

리액트의 함수 컴포넌트

리액트의 함수 컴포넌트는 Props가 입력으로, JSX Element가 출력으로 나간다.

여기에는 그 어떤 Side Effect도 없고, 순수 함수로 작동된다.

function SingleTweet({ writer, body, createdAt }) {
  return <div>
    <div>{writer}</div>
    <div>{createdAt}</div>
    <div>{body}</div>
  </div>
}

하지만, 보통 React 애플리케이션을 작성할 때는 AJAX요청이 필요하거나 LocalStorage, 타이머 같은 리액트와 상관 없는 API들을 사용하는 경우가 발생할 수 있는데, 이는 전부 Side Effect이다.

리액트는 이런 Side Effect를 다루기 위한 Hook인 Effect Hook를 제공한다.

Effect Hook

useEffect()

→ 첫번째 인자에는 함수가 들어가고, 두번째 인자는 이것을 컨트롤하고 싶을때 입력한다.

컴포넌트가 생성된 후 처음 화면에 첫번째 인자의 함수의 실행된 결과가 렌더링 되며, 컴포넌트가 렌더링 될 때마다 실행된다.

때문에 최초 생성시에만 실행하고 싶으면, 두번째 인자에 빈배열 []을 입력하거나,

원하는 요소가 실행될 때만 실행하고 싶다면 배열 안에 해당 요소, 변수를 입력하면 해당 요소, 변수가 실행될 때만 첫번째 인자의 함수가 실행되어 렌더링된다.

Updated: