jam 블로그

[React] React 기초 본문

개발 및 관련 자료/WEB

[React] React 기초

kid1412 2020. 2. 18. 09:45
반응형

React의 전반적인 것

Created: Feb 14, 2020 4:08 PM

React

React는 Facebook에서 만든 SPA(Single Page Application)을 만들기 위해 고안된 언어입니다. 비슷한 것으로는 Vue, Angular가 있습니다.

설치 및 실행

# node를 먼저 설치 후 진행해야합니다.
# node 설치 후
# create-react-app은 그간 설정하기 어려웠던 webpack 등을 자동으로 만들어주는 명령어 입니다.
npm create-react-app project-name
cd project-name

# 실행 시 localhost:3000으로 가상 서버가 띄워집니다.
yarn start

React 기초

해당 글은 16.12 최신 버전을 기반으로 작성하였습니다. project에서 index.jsx를 첫 기준으로 잡고 설명을 하겠습니다. 또한 문서 순서는 https://ko.reactjs.org/docs/getting-started.html 에서 주요 개념 파트 부분과 Hook을 참고하였습니다.

문법

React에서 개발 시 2가지 방법이 있습니다. Class를 사용하는 방법과 Function을 사용하는 방법인데 최신 기술인 React hook을 사용하기 위해 본 글에서 function으로 작업을 합니다.

JSX

React는 JSX라는 Javascript를 확장한 문법을 지원합니다.

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

// ReactDOM.render는 index.jsx에서 한번만 사용하면 되며, App component를 
// index.html의 root element안에 rendering 하겠다는 의미 입니다.
ReactDOM.render(
  <App />, //이 부분이 JSX
  document.getElementById('root')
);
// <App />과 같이 태그 안이 비어있다면 />로 바로 닫아주어야 합니다. 
// <App></App>과 같이 태그 사이에 아무 값이 없으면 비어있다고 말합니다.

Component & Props

Component는 Props라는 인자를 받은 후 그것을 어떻게 화면에 렌더링 할 것 인가를 정의한 함수라고 보시면 됩니다. 아래 소스는 Props는 없고 가장 기초적인 Component의 형태를 보여 줍니다.

// App.js
import React from 'react';
import logo from './logo.svg';
import './App.css'; // CSS 스타일 파일 로드

// 아래 함수가 기본적인 React 함수형 방식입니다.
function App() {

// return 할때 ()로 묶어서 Tag를 감싸야 제대로 Return 됩니다.
  return (
// 하단은 HTML과 같습니다.
// 다른점은 Element의 class를 지정할 때는 className으로 지정해야합니다.
    <div className="App">
      <header className="App-header">
/* 
    {logo} 표시는 svg 파일을 넣을 때 씁니다. 
    return에서 특수한 값을 넣을때는 {}를 사용합니다. 
*/
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

// 다른 곳에서 import를 하기 위해 정의를 해줍니다.
export default App;

Props는 다음과 같이 사용합니다.

// A.js
import React from 'react';
import B from './B';

function A() {
    return (
        <B name="jaemin" />
    );
}

// B.js
import React from 'react';

function B(props) {
    return (
        <div>
            {props.name}
        </div>
    )
}

export default B;

State & Lifecycle

State는 각 Component들에서 어떠한 값을 저장하기 위한 공간이라고 보시면 됩니다.

Class로 개발 시에 State는 하단에 Source를 봐주시면 되며, function에서 사용 할 때는 useState 구문을 참고해주세요.

LifeCycle은 해당 Component에서 Rendering이 되는 시점이나 변경 되는 시점에 추가적인 기능이나 다른 조작을 할 때 사용합니다.

상세한 Lifecycle은 class 방식으로 개발 시에 쓸 수 있습니다. function으로 개발 시에는 하단에 useEffect 문법을 참고해 주세요.

하단은 Class로 개발 시에 쓸 수 있는 lifecycle을 렌더링 시점으로 보여주는 이미지 입니다.

React/2.png

import React, {Component} from 'react';

// Class 방식
class Product extends Component {
  constructor(props){
    super(props);
        // 위에서 설명이 나온 state입니다.
        // 첫 초기화를 제외 하고는 this.state를 바로 넣으면 안됩니다.
    this.state = {productId: '', qty: 0, isCart: true}
  }

  addToCart = (pid) => (
        // state를 변경 하기 위해서는 다음과 같이 this.setState를 사용해야 합니다.
    this.setState((state) => (
      {productId: pid, qty: state.qty + 1}
    ))
  );

  removeCart = () => (
    this.setState({isCart: false})
  );

  render() {
    return(
      <div>
        <button onClick={() => this.addToCart(1)}>Add to Cart</button>
        <button onClick={() => this.addToCart(2)}>Add to Cart</button>
        <button onClick={() => this.addToCart(3)}>Add to Cart</button>
                // state의 값을 가져와 쓰고 싶을 경우 this.state.XXX 로 가져와서 쓸 수 있습니다. 
        { this.state.isCart && <Cart productId = {this.state.productId} qty={this.state.qty} />}
        { ! this.state.isCart && <h3>Cart has been removed</h3>}
        <button onClick={this.removeCart}>Remove Cart</button>
      </div>
    )
  }
}

class Cart extends Component {
  constructor(props){
    super(props);
    this.state = {qty: this.props.qty}
  }

  static getDerivedStateFromProps(props, state) {
    if(props.qty !== state.qty) {
      return {qty: props.qty}
    }
    return null;
  }

    // 첫 페이지가 마운트(모든 렌더링이 다 끝나고) 실행 됩니다. 
    // 여기서 setState를 할 경우 또 다시 렌더링이 발생하면 무한 루프에 빠질 수 있습니다.
  componentDidMount() {
    console.log('Invoked immediately after component render');
  }

    // Props나 State가 새로 갱신 되었을 경우 (setState 등) 발생 합니다.
  shouldComponentUpdate(nextProps, nextState) {
    if(this.props.qty !== nextProps.qty) {
      console.log('should component update');
      return true;
    }
    return false;
  }

    // 위에서 Props나 State가 반영이 다 된 후 발생 합니다. 
  componentDidUpdate(prevProps, prevState){
    if(this.props.productId !== prevProps.productId){
      console.log('component updated');
    }
  }

    // 페이지를 빠져 나가거나 Component가 해지 될 경우 발생 합니다.
  componentWillUnmount() {
    console.log('component is unmounted and destroyed');
  }

  render(){
    return(
      <div>
        <h2>Cart Items ({this.state.qty})</h2>
      </div>
    )
  }
}

export default Product;

이벤트 처리하기

기존에 Javascript의 이벤트 처리 방법과 거의 동일하지만 몇몇 차이점이 있습니다.

// 기존 HTML 마우스 클릭 이벤트
<button onclick="activateLasers()">
  Activate Lasers
</button>

// React에서 마우스 클릭 이벤트 
// onclick이 아닌 onClick이고 뒤에는 함수명만 써주면 됩니다.
<button onClick={activateLasers}>
  Activate Lasers
</button>

// 만약 클릭시 특정 값을 함수에 보내고 싶은 경우
// e는 마우스 event 입니다.
<button onClick={(e)=> this.activateLasers(e, "test")}>
  Activate Lasers
</button>

조건부 렌더링

개발 하다보면 렌더링 시에 조건에 따라 다른게 화면이 보여주고 싶을 경우 다름과 같이 하면 됩니다.

// 조건 부분을 따로 함수로 빼서 return으로 보내서 나누는 방법
function Block(isBlack) {
    if(isBlack) {
        return (<Black />);
    } else {
        return (<White/>);
    }
}

function ColorBlock() {
    const block = Block(true);
    return (
        <div>
            {block}
        </div>
    );
}

// 렌더하는 부분에서 if 삼항식으로 나누는 방법
// 복잡한 렌더가 아니면 보통 이렇게 많이 합니다.
function ColorBlock() {
    return (
        <div>
            {isBlack ? <Black/> : <White/>}
        </div>
    );
}

리스트 & Key

Element를 반복해서 찍어 내어야 할 때는 map를 사용하면 되며 각 Element를 React에서 구분할 수 있는 key를 넣어 줘야 합니다.

function TodoList() {
    // todos를 가져오는 함수가 있다고 쳤을 경우
    // Todos = [{id:1, todo:"코테 준비"},{id:2, todo:"뒹굴거리기"}]
    const Todos = getTodos();
    return (
        <ul>
            {
                // index는 map에서 제공하는 index입니다. 
                Todos.map((todo, index) => {
                    // key는 맘대로 정해도 되는데 index를 쓰거나 데이터 안에 있는 id를 씁니다.
                    <li key={todo.id}>{todo.todo}</li>
                }
            }
        </ul>
    );
}

Hook

Hook은 React 16.8에 추가되었습니다. function 함수에서 Class에서만 되었던 기능들을 쓸 수 있게 된 기능입니다. 내용은 https://velog.io/@velopert/react-hooks 링크에서 참고하였습니다.

useState

useState는 class에서 this.state와 this.setState를 대체하는 함수입니다.

import React, { useState } from 'react';

function Counter() {
    // value는 state의 값이며 setValue는 value에 값을 넣는 함수입니다.
    // useState(0)은 value의 값을 0으로 초기화 한다는 의미입니다. 
    // 아래를 class의 this.state로 바꾸면 
    // this.state.value = 0; 과 같습니다.
  const [value, setValue] = useState(0);
  return (
    <div>
      <p>
        현재 카운터 값은 <b>{value}</b> 입니다.
      </p>
      <button onClick={() => setValue(value + 1)}>+1</button>
      <button onClick={() => setValue(value - 1)}>-1</button>
    </div>
  );
};

useEffect

useEffect는 class에서 LifeCycle를 간소화한 함수입니다.

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

function Info() {
    // useState를 사용하여 name, nickname을 두개 설정 합니다. 
  const [name, setName] = useState('');
  const [nickname, setNickname] = useState('');

    // useEffect는 아래와 같이 쓸 경우 setState가 일어날 때 마다
  // (여기서는 setName, setNickname) console.log가 찍힙니다.
  useEffect(() => {
    console.log('렌더링이 완료되었습니다!');
  });

    // 여기서는 첫 페이지 접속 후 가장 처음 렌더링 될 때만 발생 합니다. 
    // 함수 끝에 [] 넣을 경우에만 됩니다.
    useEffect(() => {
        console.log('마운트 될 때만 발생합니다.');
    }, []);

    // 아래와 같이 배열에 name 같은 변수를 넣을 경우 
    // 해당 변수가 set이 될 때만 실행 됩니다. 
    useEffect(() => {
        console.log('특정값 얻데이트 될 때만 실행됩니다. ');
    },[name]);

    // return에 함수를 넣어둘 경우 component가 연결이 끊기거나 
    // 페이지 나갈 시에 실행 됩니다.
    useEffect(() => {
        return () => {
            console.log('component가 unmount 될 때만 실행됩니다.');
        };
    });

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

  const onChangeNickname = e => {
    setNickname(e.target.value);
  };

  return (
    (...)
  );
};

export default Info;

useContext

useContext는 Global로 state를 관리하는 hooks API입니다. 보통 store는 항상 component를 따라가다보니 하위 component나 부모 component에 state를 전달하려면 props로 해야하는 불편함을 해결해 줍니다.

자세한 설명은 아래 링크로 대체 합니다.

https://velog.io/@velopert/typescript-context-api

useReducer

useReducer는 Redux처럼 component에서 더 다양한 상황에 따라 다양한 상태를 다른 값으로 업데이트 해줄때 사용합니다.

리듀서는 현재 상태와 업데이트를 위해 필요한 정보를 담은 액션값을 전달 받아 새로운 상태를 반환하는 함수 입니다. 리듀서는 항상 불변성을 지켜줘야 합니다.

상세 내용은 아래 링크로 대체합니다.

https://velog.io/@public_danuel/trendy-react-usereducer

useMemo & useCallback

useMemo와 useCallback은 퍼포먼스 최적화와 가독성에 도움 주는 함수들입니다.

내용이 길어 상세 내용은 아래 링크로 대체합니다.

https://velog.io/@public_danuel/trendy-react-usememo

useRef

useRef는 컴포넌트 안에서 정의한 html의 tag에 직접 다루어야 할 경우 입니다. 아래 링크로 대체합니다.

https://velog.io/@public_danuel/trendy-react-useref

그 이외

axios

비동기로 api와 통신 하기 위한 라이브러리. jQuery의 ajax와 같은거라 보면 됩니다.

'개발 및 관련 자료 > WEB' 카테고리의 다른 글

HTTP/3  (0) 2020.11.18
[React] React 기초  (0) 2020.02.18
React Webpack (babel4 + typescript) 작성하기  (0) 2019.11.11
[es6] const, let  (0) 2019.10.20
[es6] destructuring assignment  (0) 2019.10.20
[es6] parameter  (0) 2019.10.20
0 Comments
댓글쓰기 폼