본문 바로가기
깊게 파고들기

깊게 파고들기 - React

by hustle-ing 2023. 4. 19.

React란?

리액트는 프론트엔드 개발을 위한 JavaScript 오픈소스 라이브러리이다.
HTML, CSS, JavaScript로도 충분한데 왜 리액트를 사용하는 것일까?

 

React의 특징

1. 선언형(Declarative)

코드를 자세히 분석하지 않고도 코드의 의도를 분명히 알 수 있다는 뜻이다. HTML / CSS / JS로 나눠적기보다는,   리액트는 하나의 파일에 명시적으로 작성할 수 있게 JSX를 활용한 선언형 프로그래밍을 지향한다.

 

2. 컴포넌트 기반(Component-Based)

리액트는 하나의 기능 구현을 위해 여러 종류의 코드를 묶어둔 컴포넌트를 기반으로 개발한다. 컴포넌트로 분리하면 서로 독립적이고 재사용이 가능하기에, 기능 자체에 집중하여 개발할 수 있다. 

 

3. 범용성(Learn Once, Write Anywhere)

리액트는 JavaScirpt 프로젝트 어디에든 유연하게 적용될 수 있다. 프라임워크는 한 생태계의 종속되지만, 리액트는 라이브리러이기에 기존에 개발하던 코드를 뒤엎지 않고도 일부만 고쳐서 사용할 수 있다. 또한 리액트 네이티브로 모바일 개발도 가능하다.

 

JSX?

JavaScript XML의 줄임말이다. 리엑트에서 UI를 구성할 때 사용하는 문법으로 JavaScript를 확장한 문법이다. 우리가 작성한 JSX를 Babel이 브라우저가 이해할 수 있는 JavaScript로 컴파일한다. 그 후에, 브라우저가 JavaScript를 읽고 화면에 렌더링할 수 있다.

 

JSX의 주요 문법들

 -하나의 엘리먼트 안에 모든 엘리먼트가 포함되어야 한다. JSX에서 여러 엘리먼트를 작성하고자 하는 경우, 최상위에서 opening tag와 closing tag로 감싸주어야 한다.

- CSS class 속성을 지정하려면 class가 아닌 className으로 표기해야한다.

- JSX에서 JavaScript를 쓰고자 한다면, 꼭 {중괄호}를 써야한다. 중괄호를 쓰지 않으면 일반 텍스트로 인식한다.

- 리엑트의 엘리먼트가 JSX로 작성되면 "대문자"로 시작해야 한다. 이렇게 대문자로 작성된 JSX 컴포넌트를 따로 사용자 정의 컴포턴트라고 부른다.

- 조건부 렌더링은 삼항연사자를 이용하여야만 한다.

- React에서 여러 개의 HTML 엘리먼트를 표시할 때는 "map()" 함수를 사용한다.
map 함수를 사용할 때는 반드시 "key" JSX 속성을 넣어야한다.

 

 

리엑트로 엘리먼트 생성하기 예제

 
import React from "react";
import "./styles.css";

function App() {
const user = {
firstName: "React",
lastName: "JSX Activity"
};

function formatName(user) {
return user.firstName + " " + user.lastName;
}
// JSX 없이 활용한 React
return React.createElement("h1", null, `Hello, ${formatName(user)}!`);

// JSX 를 활용한 React
// return <h1>Hello, {formatName(user)}!</h1>;
}

export default App;

 

Props

외부로부터 전달 받은 값

 

How to use props

1. 하위 컴포넌트에 전달하고자 하는 값과 속성을 정의한다.

2. props를 이용하여 정의된 값과 속성을 전달한다.

3. 전달받은 props를 렌더링 한다.

 

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child text={"I'm the eldest child"} /> 
    </div>
  );
}

function Child(props) {
  console.log("props : ", props); // {text : "I'm the eldest child"}
  return (
    <div className="child">
      <p>{props.text}</p>
    </div>
  );
}

export default Parent;
 

 

 

State

내부에서 변화하는 값

 

useState 사용법

React에서는 state를 다루는 방법 중 하나로 useState라는 특별한 함수를 제공한다.

useState를 이용하기 위해서는 React로 부터 useState를 불러와야 한다.

import { useState } from "react";

이후 useState를 컴포넌트 안에서 호출해 준다. useState를 호출한다는 것은 "state"라는 변수를 선언하는 것과 같다. 일반적인 변수는 함수가 끝날 때 사라지지만, state 변수는 React에 의해 함수가 끝나도 사라지지 않는다. 

function CheckboxExample() {
  const [ state 저장 변수, state 갱신 함수 ] = useState(state 초기값);

완성된 체크박스 컴포넌트 예시

function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);

  const handleChecked = (event) => {
    setIsChecked(event.target.checked);
  };

  return (
    <div className="App">
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
    </div>
  );
}

 

 

React에서의 이벤트 처리

<button onClick={handleEvent}> Event </button>

참고로 HTML에서의 이벤트 처리의 방식은 아래와 같다

<button onclick="handleEvent()"> Event </button>

 

onChange

<input> <textarea> <select>와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는 데 사용된다. React에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state로 관리하고 업데이트한다. onChange 이벤트가 발생하면 e.target.value를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있다. 컴포넌트 return 문 안의 input태그에 value와 onChange를 넣어준다. onChange는 input의 텍스트가 바뀔 때마다 발생하는 이벤트이다. 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState를 통해 새로운 state로 갱신한다.

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
      <input type="text" value={name} onChange={handleChange}></input>
      <h1>{name}</h1>
    </div>
  )
};

 

 

 

 

onClick

사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트이다. 버튼이나 <a> tag를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트이다.

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
      <input type="text" value={name} onChange={handleChange}></input>
      <button onClick={alert(name)}>Button</button>
      <h1>{name}</h1>
    </div>
  );
};

위에 예시에 버튼을 추가하여 버튼 클릭시 input tag에 입력한 이름이 alret를 통해 알림창이 팝업 되도록 코드를 추가해 보았다. onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나, 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 한다.

// 함수 정의하기

return (
  <div>
	...
    <button onClick={() => alert(name)}>Button</button>
	...
  </div>
  );
};

// 함수 자체를 전달하기

const handleClick = () => {
  alert(name);
};

return (
  <div>
      ...
    <button onClick={handleClick}>Button</button>
      ...
  </div>
  );
};
 

Side Effect(부수효과)

함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수는 Side Effect가 있다고 한다. 리액트에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나, 이벤트를 활용해 DOM을 직접 조작할때 Side Effect가 발생했다고 한다.

 

전역 변수 foo를 bar라는 함수가 수정하는 예제

let foo = 'hello';

function bar() {
  foo = 'world';
}

bar(); // bar는 Side Effect를 발생시킵니다!

 

 

 

Pure Function(순수 함수)

오직 함수의 입력만이 함수의 결과에 영향을 주는 함수를 순수 함수라고 한다. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치거나, 함수가 입력으로 전달된 값을 수정할 경우 순수 함수라고 부를 수 없다. 순수 함수의 특징 중 하나는 어떠한 전달 인자가 주어질 경우 항상 똑같은 값이 리턴됨을 보장한다. 그래서 예측 가능한 함수이다.

function upper(str) {
  return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않습니다 (Immutable)
}

upper('hello') // 'HELLO'

 

 

 

React의 함수 컴포넌트

React의 함수 컴포넌트는 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 Effectd이다. 리액트에서는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.

댓글