React 기본


🍦 리액트 관련 개념

JSX

  • JS에 XML을 추가한 문법
  • 보통 리액트에서만 사용
  • HTML 문서 구조를 JS에서도 사용 가능.
  • 그러나 이를 읽기 위해서는 Babel이라는 컴파일러가 필요!
  • Babel

  • JS의 컴파일러
  • 과거 ES6가 나오고 몇몇 브라우저가 ES6를 지원하지 않는 것을 ES5 문법으로 변환해주던 기능을 했음
  • 요즘은 이러한 역할은 필요가 없으므로 다른 추가적인 언어들에 대한 컴파일러 역할을 한다.
  • Webpack

  • 여러 개의 파일을 하나의 파일로 합쳐주는 모듈 번들러(Module Bundler)
  • 웹 개발에 여러 기능이 추가되기 시작하니 용량 문제가 생겼다.
  • 이를 해결하기 위해 등장한 것이 Webpack이다.
  • 필요한 기능을 필요한 순간에 모듈 형태로 불러와서 사용을 하고, 배포할 때에는 필요 없는 기능은 다 빼고 빌드를 하는 것을 도와준다.
  • 의존성이 있는 모듈을 모아서 하나의 파일로 만들어준다.
  • 🧇 Component

  • 리액트로 만들어진 앱을 이루는 최소한의 단위
  • 리액트는 컴포넌트 단위로 페이지 새로고침이 가능하여 리소스 절약 및 부드러운 사용자 경험을 제공한다.
  • 데이터는 속성(props)으로 받고, 상태(state)에 따라 View를 변화할 수 있다.
  • 독립적으로 구성되어 재사용이 편리하다.
  • 컴포넌트에는 클래스형 컴포넌트와 함수형 컴포넌트가 있다.
  • 클래스형 컴포넌트

    import React, {Component} from 'react';
    class ClassComponent extends Component {
    render() {
    return(
    <h1>Class Component 입니다.</h1>
    );
    }
    }
    export default ClassComponent;
  • 최초에 사용되었던 컴포넌트
  • 컴포넌트 자체가 JS의 Class와 유사하다.
  • state와 라이프 사이클이라는 리액트의 장점을 사용할 수 있다.
  • 그러나 메모리 자원도 더 필요하고 느리다.
  • render라는 함수를 사용해야만 그릴 수 있다.
  • 최근에는 함수형 컴포넌트를 사용하는 추세이다.
  • 함수형 컴포넌트

    const FunctionComponent = () => {
    return <div>Funtional Component 입니다</div>
    };
    export default FunctionComponent;
  • 구조 자체가 클래스에 비해 단순하다.
  • 메모리도 자원도 덜 필요하고 빠르다.
  • 과거에는 state와 라이프사이클 기능 사용이 불가능했지만 최근에는(16버전부터) Hooks라는 기능의 도입으로 같은 역할의 수행이 가능하다.
  • 🥨 JSX 문법

    ClassName

  • JS에 객체를 만들어내는 틀의 Class가 존재하기 때문에 JSX에서는 DOM 요소에 class를 부여할 때 className이라고 써야한다.
  • function App() {
    const str = 'Hello, JSX World!'
    return (
    <div className="App">
    {str}
    </div>
    );
    }
    export default App;

    { } 중괄호

  • {} 안에 JS 문법을 사용할 수 있다.
  • function App() {
    const str = 'Hello, JSX World!'
    return (
    <div className="App">
    {str}
    </div>
    );
    }
    export default App;

    Inline Style 적용

  • 인라인 스타일을 적용할 때에도 {}로 전달해야 한다.
  • JS문법을 쓰겠다는 {} 안에 객체를 전달하는 것이다.
  • function App() {
    return (
    <div className="App">
    <div style={{ fontSize: "32px" }}>인라인 스타일</div>
    </div>
    );
    }
    export default App;
  • 변수(객체)로 선언해서 전달할수도 있다.
  • function App() {
    const fontStyle = { fontSize: "32px" }
    return (
    <div className="App">
    <div style={fontStyle}>인라인 스타일</div>
    </div>
    );
    }
    export default App;

    kebab-case → camelCase

  • JS에서 - 는 빼기의 의미가 있으므로 기존 kebab-case로 표현하던 것을 camelCase로 표현해야 한다.
  • 이는 style 또는 클래스를 정할 때 적용한다.
  • function App() {
    return (
    <div className="App">
    <div style={{ fontSize: "32px", backgroundColor: "orange" }}>인라인 스타일</div>
    </div>
    );
    }
    export default App;
  • ex) font-size → fontSize,
  • EventListener

  • 리액트에서는 여기서도 camelCase를 사용한다.
  • onclick → onClick
  • onClick = { 클릭 되었을 때 실행할 JS 코드 }
  • function EventHandler() {
    return (
    <span
    onClick={() => {
    console.log('클릭됨!');
    }}
    >
    클릭!
    </span>
    );
    }
    export default EventHandler;
  • 위처럼 () ⇒ 를 사용하지 않고 바로 사용하면 바로 실행되어버린다.
  • 따라서 위처럼 익명함수로 사용해야 한다.
  • 함수를 따로 선언해서 전달하는 것도 가능하다.
  • function EventHandler() {
    function printConsole() {
    console.log('클릭됨!');
    }
    return <span onClick={printConsole}>클릭!</span>;
    }
    export default EventHandler;
  • 여기서도 함수명 뒤에 ()를 붙이게 되면 바로 실행이 되어버린다.
  • 🏈 State

  • 컴포넌트가 가지는 상태
  • JS의 변수처럼 사용할 수 있다.
  • useState

  • useState를 사용하려면 import 해야 한다.
  • import { useState } from 'react';
  • 다음과 같이 사용하여 state와 setState를 선언해준다.
  • const [state, setState] = useState(초기값);
  • useState는 state가 이전의 값과 달라지면 해당 컴포넌트만을 다시 렌더링한다.
  • 예시로 아래처럼 사용할 수 있다.
  • import { useState } from 'react';
    export default function State() {
    const [name, setName] = useState('장경은');
    const convertLang = () => {
    name === '장경은' ? setName('JKE') : setName('장경은');
    };
    return (
    <div>
    <button onClick={convertLang}>/영 변환!</button>
    <div>{name}</div>
    </div>
    );
    }

    State와 변수

    import { useState } from 'react';
    export default function StateAndVar() {
    const [state, setState] = useState(0);
    let a = 0;
    function plus() {
    a++;
    console.log(`state: ${state}, variable: ${a}`);
    }
    return (
    <div>
    <h1>
    {state} / {a}
    </h1>
    <button
    onClick={() => {
    setState((cur) => cur + 1);
    plus();
    }}
    >
    +1
    </button>
    </div>
    );
    }
  • state 값이 변형되면 state를 정의한 함수(컴포넌트)가 다시 랜더링된다.
  • 따라서 state값이 변경될 때마다 let a = 0이라고 선언한 코드가 다시 실행되어 변수 a는 ++를 해주더라도 0과 1에 머물게 된다. (console 에는 직전에 +1 해주었으므로 1로 찍힘)
  • State와 Reference Type

    import { useState } from 'react';
    export default function StateProblem() {
    const [state, setState] = useState([0]);
    console.log(state);
    return (
    <div>
    {state}
    <br />
    <button
    onClick={() => {
    state[0] = 1;
    setState(state);
    console.log(state);
    }}
    >
    1로 만들기
    </button>
    </div>
    );
    }
  • 위 코드에서 1로 만들기 버튼을 눌러도 콘솔에는 [1]이 찍히지만 숫자 0이 1로 랜더링되지는 않는다.
  • 그 이유는 다음과 같다.
  • 랜더링되게 하기 위해서는?
  • import { useState } from 'react';
    export default function StateProblem() {
    const [state, setState] = useState([0]);
    console.log(state);
    return (
    <div>
    {state}
    <br />
    <button
    onClick={() => {
    setState([1]);
    console.log(state);
    }}
    >
    1로 만들기
    </button>
    </div>
    );
    }
  • 위 처럼 작성하면 [1]이라는 새로운 배열을 state에 세팅해주기 때문에 주소값이 변경되어 랜더링 되는 것을 볼 수 있다.
  • import { useState } from 'react';
    export default function StateProblem() {
    const [state, setState] = useState([0]);
    console.log(state);
    return (
    <div>
    {state}
    <br />
    <button
    onClick={() => {
    state[0] = 1;
    const copyArr = [...state];
    setState(copyArr);
    console.log(state);
    }}
    >
    1로 만들기
    </button>
    </div>
    );
    }
  • 또는 이런식으로 사용해도 새로운 배열이 들어오는 것이기 때문에 주소값이 변경되는 것이다. (랜더링이 된다.)
  • 따라서 배열 또는 객체로 State 값을 사용해야 한다면 이것이 JS의 Reference Type이라는 것을 염두에 두고 사용해야 한다.
  • 🥃 Props

  • properties의 줄임말
  • 어떠한 값을 상위 컴포넌트가 하위 컴포넌트에 전달해야 할 때, props를 사용한다.
  • 자식 입장에서는 수정할 수 없다.
  • 기본 사용법

    function PropsHeader({ text }) {
    return <h1>{text}</h1>;
    }
    export default PropsHeader;
  • Props를 사용하려면 다음처럼 매개변수를 전달하듯이 전달하면 된다.
  • import PropsHeader from './components/PropsHeader';
    function App() {
    return (
    <div className='App'>
    <PropsHeader text='안녕하세요' />
    <PropsHeader text='감사해요' />
    <PropsHeader text='잘있어요' />
    <PropsHeader text='다시만나요' />
    </div>
    );
    }
    export default App;
  • 이를 사용할 때에는 다음처럼 데이터를 전달한다.
  • 여기서는 물론 여러 개의 Props를 사용할 수도 있다.
  • 여러 개의 Props 전달