[React Native] #0 React 복습: State, Props, useState, useEffect

김까치·2023년 4월 24일
0

React Native

목록 보기
1/6

React란?


React는 Facebook에서 개발한 UI 라이브러리로, 컴포넌트 기반의 JavaScript 라이브러리입니다. React는 작은 조각으로 나뉘어진 컴포넌트를 조합하여 UI를 만들 수 있도록 도와줍니다. 이러한 컴포넌트는 다른 컴포넌트에서 재사용될 수 있으며, 이는 개발자들이 코드의 재사용성을 높이고 유지보수를 쉽게할 수 있도록 도와줍니다.

React는 Virtual DOM을 사용하여 UI를 최적화합니다. 이는 React가 전체 UI를 다시 렌더링하지 않고 변경된 부분만 감지하여 최소한의 리소스로 UI를 업데이트할 수 있도록 해줍니다. 이러한 방식으로 React는 빠른 속도와 효율적인 성능을 보장합니다.

React는 state, props, useState, useEffect와 같은 개념을 사용하여 컴포넌트의 상태와 라이프사이클을 관리합니다. 이러한 개념들은 React의 기본적인 개념 중 일부이며, React를 사용하여 효율적이고 유지보수가 용이한 UI를 만들 수 있습니다.


컴포넌트란?

React에서 컴포넌트는 UI를 나타내는 작은 조각으로 이루어져 있습니다. 이러한 컴포넌트는 props를 통해 외부에서 전달되는 데이터와 state를 통해 내부에서 관리되는 데이터를 사용하여 동적인 UI를 구성할 수 있습니다.

Props는 컴포넌트가 외부에서 전달받는 데이터입니다. 이는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용됩니다. Props는 컴포넌트 내부에서 수정될 수 없으며, 읽기 전용으로 사용됩니다. 이는 부모 컴포넌트에서 전달받은 데이터를 자식 컴포넌트에서 변경하지 않도록 보호합니다.

컴포넌트에서 사용되는 데이터의 내부 상태는 state를 통해 관리됩니다. State는 컴포넌트 내부에서 변경 가능한 데이터를 의미합니다. 이는 사용자의 입력에 따라 변경될 수 있으며, setState() 메서드를 통해 업데이트할 수 있습니다. State의 변경은 React가 Virtual DOM을 이용하여 최소한의 리소스로 UI를 업데이트하는 데 사용됩니다.

컴포넌트에서 props와 state는 각각 다른 용도로 사용됩니다. Props는 컴포넌트 간의 데이터 전달을 위해 사용되며, state는 컴포넌트의 내부 상태를 관리하기 위해 사용됩니다. 이러한 구분을 통해 React는 효율적이고 유지보수가 용이한 UI를 구성할 수 있도록 도와줍니다.


State

State의 개념

React에서 컴포넌트는 상태(state)와 속성(props)을 가집니다. 상태는 컴포넌트 내부에서 변경되는 값으로, 컴포넌트의 렌더링 결과에 영향을 미칩니다. 상태는 클래스형 컴포넌트에서 this.state를 통해 접근할 수 있습니다. 함수형 컴포넌트에서는 useState Hook을 사용하여 상태를 관리합니다.

State의 사용방법

State는 컴포넌트 내부에서 변경되는 값으로, setState() 메서드를 통해 업데이트할 수 있습니다. 예를 들어, 다음 코드는 count 상태를 1씩 증가시키는 버튼을 포함한 컴포넌트의 예입니다.

import React, { useState } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

State의 제어

React에서는 상태(state)를 직접 수정하면 안 됩니다. 대신 setState() 메서드를 사용하여 상태를 업데이트해야 합니다. 예를 들어, 다음과 같이 state를 직접 수정하는 코드는 올바르지 않습니다.

// 이 코드는 올바르지 않습니다.
this.state.count = 1;

setState() 메서드는 비동기로 동작합니다. 그래서 setState() 호출이 즉시 상태를 업데이트하지 않을 수 있습니다. 이 때문에 setState()를 호출한 후에 상태를 사용하는 경우에는 이전 상태 값을 사용할 수 있습니다. 예를 들어, 다음 코드에서는 setState()를 호출한 후 count 상태 값을 증가시키지 않고 이전 값으로 출력됩니다.

import React, { useState } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    console.log(count); // 출력 결과: 0
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

위와 같은 상황에서는 useState Hook을 사용하여 상태를 업데이트할 수 있는데, useState Hook은 이전 상태 값을 가져오지 않고 바로 새로운 상태 값을 반환합니다. 이렇게 하면 이전 상태 값을 가져오지 않아도 새로운 상태 값을 업데이트할 수 있습니다.

State를 다루는 실제 예제 코드를 작성해 보겠습니다. 간단한 텍스트 입력 폼을 만들고, 해당 폼 값의 상태를 State로 관리하겠습니다.

import React, { useState } from 'react';

function TextInput() {
  const [value, setValue] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log(`Submitted value: ${value}`);
  }

  const handleChange = (event) => {
    setValue(event.target.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Enter text:
        <input type="text" value={value} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

위의 코드는 TextInput이라는 함수형 컴포넌트를 정의하는 코드입니다. 이 컴포넌트는 간단한 텍스트 입력 폼을 렌더링하고, 해당 폼의 값을 State로 관리합니다.

useState를 사용하여 value 상태와 setValue 함수를 정의합니다. value 상태는 폼에 입력된 텍스트 값으로 초기화되고, setValue 함수는 이 상태를 업데이트하는 데 사용됩니다.

handleChange 함수는 입력 값이 변경될 때마다 호출되어 setValue 함수를 호출하여 value 상태를 업데이트합니다.

handleSubmit 함수는 폼이 제출될 때 호출됩니다. event.preventDefault()를 사용하여 폼 제출 기본 동작을 취소하고, console.log를 사용하여 폼 값이 제대로 제출되는지 확인합니다.

TextInput 컴포넌트는 forminput 요소를 렌더링하고, value 상태를 input 요소의 value 속성과 연결하여 텍스트 입력을 표시합니다. handleChange 함수는 onChange 이벤트에 연결되어, input 요소의 값이 변경될 때마다 호출됩니다. handleSubmit 함수는 form 요소의 onSubmit 이벤트에 연결되어, 폼이 제출될 때 호출됩니다.

이와 같은 방식으로 State를 사용하여 컴포넌트 내부에서 데이터를 관리하고 업데이트할 수 있습니다.


Props

Props의 개념

Props는 React 컴포넌트에서 부모 컴포넌트로부터 전달받은 속성입니다. Props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용됩니다. Props는 읽기 전용이며, 자식 컴포넌트에서 직접 수정할 수 없습니다.

Props의 사용 방법

부모 컴포넌트에서 자식 컴포넌트에 Props를 전달하기 위해서는, JSX에서 컴포넌트를 사용할 때 Props를 추가하면 됩니다. 다음은 Props를 사용하여 자식 컴포넌트에 데이터를 전달하는 예시입니다.

import React from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const data = 'Hello, World!';

  return (
    <div>
      <ChildComponent data={data} />
    </div>
  );
}

위 예시에서는 ParentComponent에서 ChildComponent로 data라는 Props를 전달하고 있습니다.

Props의 제어

Props는 읽기 전용이므로 자식 컴포넌트에서 직접 수정할 수 없습니다. 대신, Props를 전달받은 자식 컴포넌트에서는 Props를 참조하여 렌더링을 할 수 있습니다.

예를 들어, 다음과 같은 코드에서 자식 컴포넌트에서 전달받은 Props를 사용하여 화면에 데이터를 출력하는 예시입니다.

import React from 'react';

function ChildComponent({ data }) {
  return (
    <div>
      <p>{data}</p>
    </div>
  );
}

위 예시에서는 ParentComponent에서 전달한 data Props를 ChildComponent에서 출력하고 있습니다.


useState

useState의 개념

React에서 상태를 관리하기 위해 사용되는 훅(Hook) 중 하나인 useState는 함수형 컴포넌트에서도 상태(state)를 사용할 수 있게 해줍니다. useState는 배열 형태로 반환되며 첫 번째 원소는 상태값, 두 번째 원소는 해당 상태값을 변경할 수 있는 함수(setter 함수)입니다.

useState의 사용 방법

useState를 사용하기 위해서는 다음과 같이 코드를 작성합니다.

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState는 상태값(count)과 이 값을 변경할 수 있는 함수(setCount)를 반환합니다. 위의 코드에서는 count의 초기값을 0으로 지정하고, setCount를 이용해 버튼을 클릭할 때마다 count 값을 1씩 증가시켜주고 있습니다.

useState를 이용한 컴포넌트 상태 관리

useState를 이용하면 함수형 컴포넌트에서도 상태를 사용할 수 있게 됩니다. useState를 이용하여 상태를 관리할 때는 상태값과 상태를 변경하는 함수를 useState의 반환값으로 받아와서 사용합니다. 이를 통해 상태를 변경할 때마다 컴포넌트를 다시 렌더링하게 됩니다. 따라서 상태값에 따라 화면이 변경되는 컴포넌트를 만들 수 있습니다.


useEffect

useEffect의 개념

React 컴포넌트는 마운트, 언마운트, 업데이트 등 여러 라이프사이클을 가지고 있습니다. useEffect hook은 컴포넌트에서 라이프사이클에 맞게 처리할 로직을 작성할 수 있게 해주는 hook입니다. 컴포넌트가 마운트, 언마운트, 업데이트될 때 호출되는 함수를 등록할 수 있습니다.

useEffect의 사용 방법

useEffect hook은 아래와 같은 형식으로 작성됩니다.

useEffect(() => {
  // 라이프사이클에 따른 로직 처리
}, [의존성 배열]);

첫 번째 인자는 컴포넌트가 마운트되거나, 업데이트될 때 실행할 로직을 작성합니다. 두 번째 인자로는 배열을 넘겨주는데, 이 배열에는 useEffect에서 참조하는 상태나 props를 넣어줍니다. 배열 안에 지정한 상태나 props가 변경될 때마다 첫 번째 인자에 작성한 로직이 실행됩니다. 만약 빈 배열을 넘겨준다면, 컴포넌트가 마운트될 때 한 번만 실행됩니다.

useEffect를 이용한 컴포넌트 라이프 사이클 관리

useEffect는 컴포넌트의 라이프사이클에 따른 로직 처리를 위해 다양한 용도로 사용됩니다. 예를 들어, 컴포넌트가 마운트될 때 데이터를 불러오는 경우, 상태가 업데이트될 때마다 특정 동작을 수행하는 경우, 컴포넌트가 언마운트될 때 정리 작업을 수행하는 경우 등에 사용됩니다.

useEffect에서 리턴되는 함수는 컴포넌트가 언마운트되거나 업데이트될 때 정리 작업을 수행할 수 있도록 합니다. 만약 언마운트 시에만 정리 작업을 하고 싶다면, useEffect hook에 빈 배열을 넘겨주면 됩니다.

useEffect(() => {
  // 컴포넌트 마운트 시에 실행할 로직
  return () => {
    // 컴포넌트 언마운트 시에 실행할 로직
  };
}, [의존성 배열]);

예를 들어, useEffect를 사용하여 컴포넌트가 마운트될 때 API에서 데이터를 가져오고 해당 데이터를 state에 저장하려는 경우 다음과 같은 코드를 작성할 수 있습니다.

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

function MyComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {
    // 컴포넌트가 마운트될 때 API에서 데이터 가져오기
    fetch('https://example.com/api/data')
      .then(response => response.json())
      .then(data => {
        setData(data); // 데이터를 state에 저장
      });
  }, []);

  return (
    <div>
      {/* state에 저장된 데이터를 사용하여 UI 렌더링 */}
      {data.map(item => (
        <p key={item.id}>{item.name}</p>
      ))}
    </div>
  );
}

위의 코드에서 useEffect 훅은 빈 배열 []을 두 번째 인자로 전달하여 컴포넌트가 처음으로 렌더링될 때 한 번만 실행되도록 설정합니다. useEffect 훅은 비동기 함수 fetch를 호출하여 API에서 데이터를 가져옵니다. 그리고 데이터가 로드되면 setData 함수를 호출하여 해당 데이터를 state에 저장합니다. 마지막으로 data state를 사용하여 UI를 렌더링합니다. 이렇게 하면 API에서 가져온 데이터가 성공적으로 렌더링되고 화면에 표시됩니다.

다음은 컴포넌트가 언마운트되거나 업데이트될 때 cleanup 함수를 호출하는 useEffect 예시입니다.

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

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('mounted');
    return () => {
      console.log('unmounted or updated');
    };
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

이 예시에서는 useEffect의 콜백 함수가 컴포넌트가 마운트될 때와 count의 값이 업데이트될 때 호출됩니다. 마운트될 때는 "mounted"라는 문자열이 콘솔에 출력되고, 컴포넌트가 언마운트되거나 count의 값이 업데이트될 때는 "unmounted or updated"라는 문자열이 콘솔에 출력됩니다.


State vs. Props

State와 Props는 React에서 중요한 개념이며, 컴포넌트의 동작 방식을 이해하는 데 필수적입니다. 두 개념은 비슷하지만 목적과 사용 방법에 차이가 있습니다.

  • State와 Props의 차이점

State는 컴포넌트 내부에서 선언하고 관리되는 값입니다. 이 값은 컴포넌트가 렌더링될 때 변경될 수 있으며, 컴포넌트 내부에서만 접근 가능합니다. State는 컴포넌트가 자체적으로 변경 가능한 데이터를 가지고 있어야 할 때 사용됩니다.

반면, Props는 컴포넌트의 속성값으로 외부에서 전달되는 값입니다. Props는 읽기 전용이며, 컴포넌트 내부에서 변경할 수 없습니다. Props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용됩니다.

  • State와 Props의 사용 용도

State는 컴포넌트 내부에서 변경되는 값을 저장하기 위해 사용됩니다. 예를 들어, 입력 폼 컴포넌트에서 사용자가 입력한 값을 저장하거나, 상태 변화에 따라 UI를 업데이트하기 위한 데이터를 저장하는 데 사용됩니다.

React에서 UI를 업데이트하기 위해 필요한 데이터를 저장하기 위해서는 state를 사용할 수 있습니다. state는 컴포넌트 내부에서 선언하며, 해당 컴포넌트 내부에서만 사용 가능합니다. state를 사용하면 데이터를 갱신할 때마다 컴포넌트가 다시 렌더링됩니다.

다음은 todo 리스트를 만드는 예시 코드입니다. 각각의 todo 아이템은 id, text, completed 프로퍼티를 가지고 있습니다. completed 프로퍼티는 해당 todo가 완료되었는지 여부를 나타냅니다.

import React, { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React', completed: false },
    { id: 2, text: 'Build a Todo App', completed: true },
    { id: 3, text: 'Deploy to Netlify', completed: false }
  ]);

  const toggleTodo = (id) => {
    setTodos(prevTodos => {
      return prevTodos.map(todo => {
        if (todo.id === id) {
          return { ...todo, completed: !todo.completed };
        } else {
          return todo;
        }
      });
    });
  };

  const todoListItems = todos.map(todo => {
    return (
      <div key={todo.id}>
        <input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} />
        <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>{todo.text}</span>
      </div>
    );
  });

  return (
    <div>
      <h2>Todo List</h2>
      {todoListItems}
    </div>
  );
}

export default TodoList;

위 코드에서 useState 훅을 사용하여 todos 상태를 선언하고, toggleTodo 함수를 작성하여 해당 todo의 completed 값을 토글하는 역할을 합니다. todoListItemstodos 배열을 map 함수를 사용하여 각각의 todo에 대한 UI를 생성합니다. 이렇게 todos 상태가 변경될 때마다 컴포넌트가 자동으로 다시 렌더링되므로, UI가 항상 최신의 상태를 유지할 수 있습니다.

Props는 컴포넌트 간에 데이터를 전달하기 위해 사용됩니다. 예를 들어, 리스트 컴포넌트에서 각 항목을 표시하기 위해 배열 데이터를 전달하거나, 다른 컴포넌트에서 컴포넌트 자체를 props로 전달하여 재사용 가능한 UI를 만드는 데 사용됩니다.

다음은 배열 데이터를 전달하는 props를 사용하여 간단한 리스트 컴포넌트를 만드는 예시입니다.

// List 컴포넌트
function List({ title, data }) {
  const listItems = data.map((item) => <li key={item.id}>{item.text}</li>);
  return (
    <div>
      <h2>{title}</h2>
      <ul>{listItems}</ul>
    </div>
  );
}

// App 컴포넌트
function App() {
  const data = [
    { id: 1, text: "리액트 공부하기" },
    { id: 2, text: "프로젝트 아이디어 구상하기" },
    { id: 3, text: "코드 리팩토링하기" }
  ];
  return (
    <div>
      <List title="오늘의 할 일" data={data} />
    </div>
  );
}

위 예시에서 List 컴포넌트는 props로 title과 data를 받습니다. data는 배열 형태의 데이터이며, 이를 이용하여 각 항목을 표시하는 리스트를 렌더링합니다. App 컴포넌트에서는 List 컴포넌트를 사용하여 데이터를 전달하고, 이를 렌더링합니다. 이렇게 props를 이용하여 컴포넌트에서 데이터를 전달하면, 같은 컴포넌트를 여러 곳에서 사용할 수 있고, 재사용성이 높아집니다.

예를 들어, 버튼 컴포넌트를 만들고 이를 여러 곳에서 재사용하고 싶다고 가정해보겠습니다. 이때, 이 버튼 컴포넌트에는 버튼 텍스트와 클릭 이벤트를 처리하는 함수가 필요합니다. 이를 props로 전달하여 컴포넌트를 재사용할 수 있습니다.

아래는 버튼 컴포넌트를 만들고, 이를 다른 컴포넌트에서 사용하는 예시입니다.

// Button 컴포넌트 정의
function Button({ onClick, text }) {
  return (
    <button onClick={onClick}>
      {text}
    </button>
  );
}

// 다른 컴포넌트에서 Button 컴포넌트 사용 예시
function App() {
  function handleClick() {
    alert("Button clicked!");
  }

  return (
    <div>
      <Button text="Click me!" onClick={handleClick} />
      <Button text="Don't click me!" onClick={() => alert("I told you not to click me!")} />
    </div>
  );
}

위 예시에서 Button 컴포넌트는 props로 textonClick 함수를 받아 사용합니다. 이를 이용하여 다른 컴포넌트에서 Button 컴포넌트를 여러 번 사용할 수 있습니다. App 컴포넌트에서는 handleClick 함수를 정의하여 이를 Button 컴포넌트의 onClick props로 전달하고 있습니다. 또한, 두 번째 Button 컴포넌트에서는 onClick props에 함수를 직접 전달하여 사용하고 있습니다.

이러한 State와 Props의 개념을 이해하고, 적절하게 활용하여 React 컴포넌트를 개발할 수 있다면, 보다 유지 보수가 용이하고 재사용성이 높은 React 애플리케이션을 개발할 수 있습니다.


마무리

이상으로 React에 대한 기본적인 내용을 알아보았습니다. React는 컴포넌트 기반의 UI 라이브러리로, 화면의 구성을 작은 단위인 컴포넌트로 쪼개어 개발하고 이를 조합하여 구성합니다. 이때 컴포넌트 내부의 상태(State)와 외부에서 전달되는 속성(Props)을 통해 컴포넌트를 제어하고 구성합니다.

useState와 useEffect는 컴포넌트 내부의 상태(State)와 라이프사이클 관리를 위해 필수적으로 알아야하는 Hook입니다. useState를 통해 상태값을 관리하고 useEffect를 통해 컴포넌트 라이프사이클에서의 작업을 수행합니다.

또한, 상태(State)와 속성(Props)의 차이점과 각각의 사용 용도를 이해하는 것은 React를 이해하는 데 중요한 요소입니다. 상태(State)는 컴포넌트 내부에서 변경되는 값으로, 컴포넌트 내부에서만 사용됩니다. 반면, 속성(Props)은 컴포넌트 외부에서 전달되는 값으로, 컴포넌트 내부에서 변경할 수 없습니다.

React는 강력한 기능과 생산성, 그리고 확장성을 제공하여 현대적인 웹 애플리케이션을 개발하는 데 매우 유용합니다. 하지만 React만으로 웹 애플리케이션을 개발하는 것이 아니라, React와 함께 다른 기술과 라이브러리를 결합하여 좀 더 완성도 높은 애플리케이션을 개발할 수 있습니다.

profile
개발자 연습생

0개의 댓글