Lsiron

JSX, Components, Props/State 본문

프론트엔드/React

JSX, Components, Props/State

Lsiron 2024. 5. 22. 02:23

1. JSX

JSX(JavaScript XML)는 React에서 사용되는 JavaScript의 확장 문법이다. JSX는 JavaScript와 HTML을 조합하여 UI를 구성할 수 있도록 도와준다. JSX는 HTML과 비슷한 문법을 가지고 있어서 React Component를 작성할 때 보다 직관적이고 가독성이 좋다.

출처: https://velog.io/@jellyjw/React-JSX%EB%9E%80

 

JSX는 Babel과 같은 트랜스파일러를 사용하여 일반 JavaScript 코드로 변환된다. JSX는 React.createElement() 함수로 변환되며, 이를 통해 Virtual DOM을 생성하고 업데이트할 수 있다. JSX를 사용하면 UI를 선언적으로 구성할 수 있으며, JavaScript 코드와 함께 사용하여 동적인 내용을 표현할 수 있다.

React에서 JSX를 사용하면 Component를 작성할 때 HTML 태그와 JavaScript 코드를 함께 사용할 수 있어서 개발자가 보다 편리하게 UI를 구성할 수 있다. JSX를 통해 React Component를 작성하면 코드의 가독성이 향상되고 개발 생산성이 증가하게 된다.

 

1) 문법 

=> JSX는 JavaScript와 XML의 결합이며, JavaScript 코드 내에 HTML 요소를 포함할 수 있다. HTML과 유사한 모양을 가지고 있지만, JavaScript 표현식을 사용할 수 있다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HTML 예제</title>
</head>
<body>
    <h1> Lsiron </h1>
</body>
</html>

 

<JSX 예시>

import React from 'react';

function App() {
    return (
        <div>
            <h1> Lsiron </h1>
        </div>
    );
}

export default App;

 

2) 속성과 이벤트 처리 

=> JSX에서 요소에 속성을 지정할 때는 중괄호({})를 사용하여 JavaScript 표현식을 넣을 수 있다. 이벤트 처리도 JavaScript 함수를 이용하여 처리할 수 있다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HTML 예제</title>
</head>
<body>
    <button onclick="alert('Button Clicked!')">Click me</button>
</body>
</html>

 

<JSX 예시>

import React from 'react';

function Button() {
    function handleClick() {
        alert('Button Clicked!');
    }

    return (
        <button onClick={handleClick}>Click me</button>
    );
}

export default Button;

 

3) 클래스와 스타일 

=> JSX에서는 HTML의 class 속성을 className으로 사용해야하고, 스타일을 지정할 때는 객체 형태로 지정해야 한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HTML 예제</title>
    <style>
        .custom-class {
            color: red;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div class="custom-class">
        Styled Div
    </div>
</body>
</html>

 

<JSX 예시>

import React from 'react';

function StyledDiv() {
    const customStyle = {
        color: 'red',
        fontSize: '20px'
    };

    return (
        <div className="custom-class" style={{customStyle}}>  // style에서 바깥쪽 중괄호는 JS객체 때문 , 안쪽은 CSS 
            Styled Div
        </div>
    );
}

export default StyledDiv;
 

 

4) 닫는태그 

=> JSX에서는 모든 요소에 대해 닫는 태그가 필요하다. 닫는 태그를 생략할 경우 컴파일 오류가 발생하므로, 모든 요소에 대해 명시적으로 닫는 태그를 작성해주어야 한다. 기존에 닫는 태그가 필요없었던 input, br, img를 포함하여 모든 태그에 닫는태그를 포함해야 한다.

import React from 'react';

function App() {
    return (
        <div>
            <h1>Lsiron</h1>
            <img src= "www.Lsiron.tistory.com" alt="" />
            <br/>
            <input type="text"/>
        </div>
    );
}

export default App;

 

5) 최상단 element는 반드시 하나

=> JSX에서는 최상위 레벨에서는 하나의 요소로 감싸져 있어야 한다. 이는 React 컴포넌트의 렌더링 규칙으로, 최상위 레벨에서는 하나의 부모 요소로 감싸져 있어야만 한다. 이를 위해 Fragment(<Fragment></Fragment>나 빈 태그(<></>)를 사용하여 여러 요소를 묶어주는 방식을 사용할 수 있다.

import React from 'react';

function App() {
    return (
        <>
            <div>
                <h1> Lsiron </h1>
            </div>
        </>
    );
}

export default App;

 

 

2. Component

React에서 Component란 UI를 구성하는 빌딩 블록이다. Component는 독립적으로 작동하며 화면의 일부분을 나타낸다. React 애플리케이션은 여러 개의 Component로 구성되어 있으며, 각 Component는 자체적인 상태(State)를 가질 수 있고 Props를 통해 데이터를 전달받아 화면을 렌더링한다.

Component는 재사용이 가능하며 모듈화된 코드를 작성할 수 있도록 도와준다. 또한 생명주기 메서드를 통해 Component의 생성, 업데이트, 제거 등의 과정을 제어할 수 있다. Component는 가독성이 뛰어나고 상태 관리가 용이하며, Props를 통해 부모 Component로부터 데이터를 전달받아 사용할 수 있다.

 

Component는 대문자로 시작해야한다.

=> React에서 Component의 이름은 대문자로 시작해야 한다. 이는 JSX에서 HTML 태그와 React Component를 구분하기 위한 규칙 중 하나다. 대문자로 시작하는 이름은 React가 해당 요소를 Component로 인식하고 처리하게 된다. Component의 이름이 소문자로 시작하면 React는 그것을 일반적인 HTML 태그로 처리한다. 따라서 React Component를 작성할 때에는 항상 이름을 대문자로 시작하여야 한다.

const MyComponent = () => {
    return <div>Hello, World!</div>;
  }
 
  ReactDOM.render(<MyComponent />, document.getElementById('root'));

 

3. Props(Properties) / State

중요개념인 props 와 state 는 React 에서 데이터를 다룰 때 사용하는 개념이다.

이 각각을 파헤치기 전에, 이 둘을 비교하며 차이점을 살펴보자.

 

Prop은 부모 컴포넌트로부터 전달되는 속성이며, 해당 컴포넌트 내에서 변경할 수 없다. 즉, 자식이 전달받은 Prop은

읽기 전용이기 때문에 직접적으로 수정할 수 없으며, 자식 컴포넌트에서는 해당 Prop을 사용할 뿐이다.

 

반면에 State는 컴포넌트 내부에서 선언하고 변경할 수 있는 데이터이다. 컴포넌트 내부에서 setState() 메서드를 통해 state 값을 변경할 수 있으며, 해당 변경은 컴포넌트 자체에만 영향을 준다. State는 컴포넌트의 상태나 동작을 관리하는데 사용되며, 사용자의 상호작용에 따라 동적으로 변경될 수 있다.

 

즉, 표로 나타내면 이렇다.

  Props State
속성 외부에서 전달 내부에서 선언 및 초기화
변경 가능성 읽기 전용 변경 가능
변경 방법 부모 컴포넌트에서 변경 불가능 setState() 메소드를 통해 변경 가능
전파 부모 -> 자식 컴포넌트 컴포넌트 내부에서만 유효

 

그럼 이제 각각 자세하게 파헤쳐보자.

 

Props(Properties)

Props(properties)는 React 컴포넌트에서 사용되는 속성(property)들을 전달하는 방식이다. Props를 사용하면 컴포넌트 간에 데이터를 전달하거나 컴포넌트의 동작을 제어할 수 있다. Props를 사용할 때는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 속성으로 값을 넘겨주는 형태로 사용된다.(자식에서 부모로, 자식에서 자식으로 전달하는 형태는 불가능하다.) 자식 컴포넌트에서는 props라는 매개변수를 받아와서 해당 값에 접근할 수 있다.

 

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

const ParentComponent = () => {
  return (
    <div>
      <ChildComponent name="Lsiron" age={28} />
    </div>
  );
}

export default ParentComponent;
// ChildComponent.js
import React from 'react';

const ChildComponent = (props) => {
  return (
    <div>
      <p>Name: {props.name}</p>
      <p>Age: {props.age}</p>
    </div>
  );
}

export default ChildComponent;

 

위 예시를 객체로 할당했을 때의 예시는 아래와 같다

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

const ParentComponent = () => {
  const info = {
    name: "Lsiron",
    age: 28
  }

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

export default ParentComponent;
// ChildComponent.js
import React from 'react';

const ChildComponent = ({props}) => { // 변수를 받아오는것이라, 중괄호를 씌워주어야한다.
  return (
    <div>
      <p>Name: {props.name}</p>
      <p>Age: {props.age}</p>
    </div>
  );
}

export default ChildComponent;

 

=> 위의 예제에서 ParentComponent는 ChildComponent를 렌더링하고 있다(부모에서 자식으로 넘겨주고 있다). ParentComponent에서 ChildComponent에게 name과 age라는 Props를 전달하고 있다.

ChildComponent는 이 Props를 받아와서 화면에 보여주는 역할을 한다. (단, ChildComponents 에서 props를 임의로 변경해서는 안된다. 변경하고싶다면 변수를 새로 지정하여 할당 해 줘야한다. 즉 props는 읽기전용이라고 생각하면 된다.)

다시 말해서, 부모는 자식의 이름을 정해주고, 자식은 그 이름으로 활동을 한다. 라고 생각하면 되겠다.

Props를 사용하여 데이터를 전달하면 컴포넌트의 재사용성이 높아지고 유지보수가 용이해진다.

아래는 컴포넌트를 재사용 하는 경우이다.

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

const ParentComponent = () => {
  return (
    <div>
      <ChildComponent name="Lsrion" age={28} />
      <ChildComponent name="Srion" age={27/>
      <ChildComponent name="Rion" age={26/>
    </div>
  );
}

export default ParentComponent;

 

DOM Element의AttributesProps 

1) 기본적인DOM Element(div, span 등)들의 Attribute는 camel Case 로 작성 해야한다.

ex) tabIndex, className등 

2) 그러나 ‘data-’ 또는‘aria-’ 로시작하는 Attribute는 예외이다.

ex) data-type, aria-label 등 

3) HTML의 Attribute와 다른이름을 가지는 Attribute가 있다.

ex) class → className, for → htmlFor등 

4) HTML의 Attribute와 다른 동작 방식을 가지는 Attribute가있다.

ex) checked(defaultChecked), value(defaultValue), style 등

 =>

checked 속성

HTML에서는 <input type="checkbox" checked="true" />와 같이 checked 속성을 사용하여 체크박스를 기본으로 체크된 상태로 표시할 수 있다. 그러나 React에서는 checked 속성을 직접 설정하여 체크박스의 상태를 관리해야 한다.

import React, { useState } from 'react';

function Checkbox() {
  const [isChecked, setIsChecked] = useState(true);

  const handleCheckboxChange = () => {
    setIsChecked(!isChecked);
  };

  return (
    <input
      type="checkbox"
      checked={isChecked}
      onChange={handleCheckboxChange}
    />
  );
}

export default Checkbox;

 

=> 위 예제에서는 useState 훅을 사용하여 isChecked 상태를 관리하고, 체크박스의 상태를 토글하는 handleCheckboxChange 함수를 정의했다. checked 속성을 isChecked 값으로 설정하고, onChange 이벤트를 통해 상태를 변경하도록 구현했다.

 

value 속성

HTML에서는 <input type="text" value="Hello" />와 같이 value 속성을 사용하여 input 요소의 기본값을 설정할 수 있다. React에서는 value 속성을 통해 input 요소의 값을 관리할 때 주의해야 한다.

import React, { useState } from 'react';

function InputField() {
  const [text, setText] = useState('');

  const handleInputChange = (e) => {
    setText(e.target.value);
  };

  return (
    <input
      type="text"
      value={text}
      onChange={handleInputChange}
    />
  );
}

export default InputField;

 

=> 위 예제에서는 useState 훅을 사용하여 text 상태를 관리하고, handleInputChange 함수를 통해 input 요소의 값이 변경될 때 상태를 업데이트하도록 구현했다. value 속성을 text 값으로 설정하여 input 요소의 값을 관리하고 있다.

이렇게 React에서는 checked와 value 속성을 HTML과 다르게 다루며, 상태를 통해 동적으로 관리하는 방식을 채택하고 있다. 이를 통해 React 컴포넌트의 상태를 한 곳에서 효율적으로 관리할 수 있다.

 

5) React에서 만 쓰이는 새로운 Attribute가 있다.

 ex) key, dangerouslySetInnerHTML등

 => key 속성은 React에서 배열을 렌더링할 때, 각 요소에 고유한 식별자를 부여하는 데 사용된다. React는 key를 사용하여 요소들을 식별하고 관리하기 때문에, 배열의 순서가 변경되어도 각 요소가 올바르게 업데이트되도록 도와준다.

import React from 'react';

function ListComponent() {
  const items = [
    { id: 1, name: 'Apple' },
    { id: 2, name: 'Banana' },
    { id: 3, name: 'Orange' }
  ];

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

export default ListComponent;

 

=> 위 예제에서는 ListComponent 컴포넌트에서 items 배열을 map 함수를 사용하여 순회하며 각 요소를 요소로 렌더링하고 있다. 

 각 요소에는 key 속성으로 item의 id 값을 부여하여 고유한 식별자를 제공하고 있다. React는 key 속성을 통해 각 요소를 고유하게 식별하고, 배열의 순서가 변경되었을 때 올바르게 업데이트하며, 성능을 최적화할 수 있다. 따라서 React에서 배열을 렌더링할 때는 key 속성을 적절히 활용하여 각 요소를 식별하는 데 유의해야 한다.

key는 배열 안 에서 형제 사이에서 고유해야 하고 전체 범위에서 고유할 필요는 없다. 두 개의 다른 배열 을 만들때 동일한 key를 사용할 수 있다.

 

State

React에서 state는 컴포넌트 내부에서 관리되는 데이터를 의미한다. state는 컴포넌트의 상태를 나타내고, 상태가 변경될 때마다 React는 자동으로 컴포넌트를 다시 렌더링한다.

 

( 왜 굳이 이렇게 하는거지? , JSX에서 만약 변수에 값을 저장하고 사용하면, 값을 변경했을때 HTML에 반영이 되지 않음. 때문에 값을 변경해주는 기능을 가진 State를 쓰는것임. 즉 State를 쓰면 재렌더링이 자동으로 된다.)

 

즉, state 는 Component 내부에서 관리하며, 상태에 따라 변하는 동적 데이터 이다. state 는 props 와 다르게 자동으로 생성되지 않아 명시적으로 state 를 기술 해야한다.

 

( 그럼 언제 변수를 쓰고 언제 State를 쓰는거지?, 자주 변경되지 않는 값이면 변수를 쓰고, 자주 변경되는 값은 State를 써주면 된다.

 

1) State의 정의

=> state는 클래스형 컴포넌트에서 constructor 메서드 내부에서 this.state를 통해 초기화하거나, useState 훅을 사용하여 함수형 컴포넌트에서 상태를 선언할 수 있다.

// 클래스형 컴포넌트에서 state 초기화
class ExampleComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }
    // ...
}

// 함수형 컴포넌트에서 useState를 사용하여 state 선언
const ExampleComponent = () => {
    const [count, setCount] = useState(0);
    // ...
};

 

2) State의 사용법

=> state를 업데이트할 때에는 setState 메서드(클래스형 컴포넌트)나 state를 업데이트하는 함수(함수형 컴포넌트)를 호출하여 상태를 변경한다.

// 클래스형 컴포넌트에서 state 업데이트
this.setState({ count: this.state.count + 1 });

// 함수형 컴포넌트에서 state 업데이트
setCount(prevCount => prevCount + 1);

 

3) State를 사용하는 경우 

=> 컴포넌트가 자체적으로 관리해야 하는 데이터가 있을 때 state를 사용한다. 예를 들어, 사용자 입력값, 화면에 표시되는 데이터 등을 state로 관리하며, 이러한 상태가 변경될 때마다 컴포넌트를 다시 렌더링한다.

import React, { useState } from 'react';

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

    const incrementCount = () => {
        setCount(prevCount => prevCount + 1);
    };

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={incrementCount}>Increase Count</button>
        </div>
    );
};

export default ExampleComponent;

 

=> 위 코드에서는 useState를 사용하여 count라는 상태 변수를 선언하고, 버튼을 클릭할 때 count 값을 1씩 증가시키는 예시를 보여주었다. 이처럼 state를 사용하여 동적인 데이터를 관리하고 상태 변경에 따라 UI를 업데이트할 수 있다.

 

4) state를 변경하는 경우

setState 메서드를 사용하여 state 변경
=> setState 메서드를 사용하여 state를 업데이트할 수 있다. setState 메서드를 호출하면 React는 변경된 state를 감지하고 자동으로 컴포넌트를 다시 렌더링한다.

import React, { useState } from 'react';

function Counter() {
  const [countsetCount= useState(0);

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

 

이전 state를 활용하는 함수형 업데이트
=> setState의 인자로 이전 state와 현재 state를 받아서 새로운 state를 반환하는 함수를 전달할 수 있다. 이를 활용하면 이전 state에 의존하는 업데이트를 수행할 수 있다

import React, { useState } from 'react';

function Counter() {
  const [countsetCount= useState(0);

  const incrementByTwo = () => {
    setCount(prevCount => prevCount + 2);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementByTwo}>Increment by 2</button>
    </div>
  );
}

export default Counter;

 

Object를 갖는 state를 만들 때 주의해야 할 점이 있다.

1. state를 업데이트할 때 객체의 불변성을 유지해야 한다. 객체를 직접 수정하는 것이 아니라, 기존 객체를 수정하지 않고 새로운 객체를 생성하여 업데이트해야 한다.

 

2. 객체를 업데이트할 때 spread 연산자나 Object.assign을 사용하여 새로운 객체를 생성하고 업데이트해야 한다. 직접 객체를 수정하는 경우 React는 상태 변경을 감지하지 못할 수 있다.

 

import React, { useState } from 'react';

const ExampleComponent = () => {
  // 배열을 useState로 선언하는 예시
  const [numbers, setNumbers] = useState([1, 2, 3]);

  // 객체를 useState로 선언하는 예시
  const [person, setPerson] = useState({ name: 'Lsiron', age: 28 });

  // numbers 배열에 새로운 숫자를 추가하는 함수
   setNumbers((current) => {
      const newNumbers = [...current, 4];
      return newNumbers;
    });
  

  // person 객체의 이름을 변경하는 함수
  setPersons((current) => {
    const newPerson = { ...current}
    newPerson.name = "siron"
    return newPerson
  });

  return (
    <div>
      <h2>Numbers: {numbers.join(', ')}</h2>
      <button onClick={setNumber}>Add Number</button>

      <h2>Person: {person.name}, Age: {person.age}</h2>
      <button onClick={setPersons}>Change Name</button>
    </div>
  );
};
export default ExampleComponent;

 

그럼 대체 useState와 setState는 무엇이길래 계속해서 언급되고 사용되는 것인가?

 

useState 함수는 React 훅 중 하나로, 함수형 컴포넌트에서 상태를 사용할 수 있도록 도와주는 함수이다. useState 함수를 사용하면 상태 값을 선언하고 업데이트할 때 사용되는 setState 함수를 함께 제공받을 수 있다.

setState 함수는 클래스형 컴포넌트에서 사용되는 메소드로, 상태를 업데이트하고 화면을 다시 렌더링할 때 사용된다. useState 함수를 사용하여 선언한 상태 변수를 업데이트할 때에는 useState로부터 제공받은 setState 함수를 사용해야 한다.

즉, useState 함수는 상태를 선언하고 업데이트할 때 사용하는 함수이며,

setState 함수는 useState로부터 제공받은 상태를 실제로 업데이트하는 함수이다.

클래스형 컴포넌트에서는 상태 값을 변경할 때 this.setState를 사용하고, 함수형 컴포넌트에서는 useState와 해당 상태를 업데이트하는 setState 함수를 사용한다.

 

예제를 보면서 자세하게 살펴보자.

import React, { useState } from 'react';

const ExampleComponent = () => {
    // useState를 사용하여 count라는 상태 변수를 선언하고 초기값을 0으로 설정
    const [count, setCount] = useState(0);

    // 버튼 클릭 시 count 값을 1씩 증가시키는 함수
    const incrementCount = () => {
        // useState로부터 제공받은 setCount 함수를 사용하여 count 값을 업데이트
        setCount(prevCount => prevCount + 1);
    };

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={incrementCount}>Increase Count</button>
        </div>
    );
};

export default ExampleComponent;

 

=> 위 코드에서 useState를 사용하여 count라는 상태 변수를 선언하고 초기값을 0으로 설정했다.

그리고 incrementCount 함수를 만들어 버튼을 클릭할 때 count 값을 1씩 증가시키도록 했다. 이때 count 값을 업데이트할 때에는 useState로부터 제공받은 setCount 함수를 사용하여 이루어진다.

 

즉, useState 함수를 통해 상태를 선언하고 setState 함수를 통해 해당 상태를 업데이트하는 것이 함수형 컴포넌트에서의 상태 관리 방식이다. 클래스형 컴포넌트에서는 this.setState를 사용하여 상태를 업데이트했던 것과 비슷한 원리이다.

 

그럼 도대체 setState 함수가 어디 있다는것일까? 위 예제에선 setCount만 보인다.

 

useState 훅을 사용하면 상태 변수와 해당 상태를 업데이트하는 함수를 함께 제공받는다.

이때 상태 변수를 업데이트하는 함수는 해당 상태의 이름 뒤에 “set”을 붙인 형태로 지어진다. 

예를 들어, count 라는 상태 변수를 useState로 선언했다면, 해당 상태를 업데이트하는 함수는 setCount로 제공된다.

이렇게 useState로부터 제공받은 업데이트 함수는 해당 상태 변수를 업데이트할 때 사용되며, 이 함수를 호출하여 상태를 업데이트할 수 있다. 따라서 위 예시에서 setCount 함수를 사용하여 count 값을 업데이트하는 것이다.

 

그럼 다시 위로 올라가서 한번 State 예제를 통해 이해도를 확인해보자. 예제들이 이해가 될 것이다.

 

 

 

Tips

면접 질문 : defendency와 devdefendency의 차이점

=> defendency는 배포용 라이브러리, devdefendency는 개발용 라이브러리

 

export 할때 default 키워드를 쓰면 이름을 바꿔서 import 가능하다.

export default Lsiron;

import Siron from './Lsiron';

 

export 할때 default 키워드를 안 쓰고 중괄호로 씌우면 중괄호로 import 해야된다.

export {Lsiron};

import {Lsiron} from './Lsiron';

 

참조: Elice Academy

'프론트엔드 > React' 카테고리의 다른 글

axios(get, post, put, delete)  (2) 2024.06.02
상태관리(Context API)  (2) 2024.06.01
Custom hook, styling, SPA와 라우팅  (0) 2024.05.30
event처리, hooks  (0) 2024.05.24
리액트 시작하기.  (0) 2024.05.19