본문 바로가기

코드스테이츠 SEB FE 41기/Section 별 내용 정리

section2/unit4/[React]Intro(9/28)

반응형

블로깅 주제

  • React Intro

1. 지금 현재, 당신의 기분이나 느낌을 표현해 주세요.

  • 다행히 오늘 데일리 코딩은 잘 풀렸다. 데일리 코딩이 잘 풀리냐 안풀리냐에 따라 오전 공부의 컨디션(?)이 달라지는 것 같다.. 나중엔 더 어려운 걸 풀텐데 멘탈 관리를 잘해야겠다. 지금은 배우는 중이라고. 금요일부터 어제까지 약 2.5일간의 비동기 여정이 끝이 났다.  고차함수, 객체지향, 비동기... 어려운 것들 싹 다 지나고 숨 좀 돌리려나 했는데 이제 리액트다! 오늘부터 진짜 시작이겠지? 걱정 반 기대 반이다. 리액트는 꼭 배워야하는 것이니까... 처음엔 다 어렵다고 생각하고 이번주도 잘 보내보자.

2. 오늘 무엇을 학습한 내용 중 지금 떠올릴 수 있는 단어를 모두 나열해 주세요.

  • React, JSX

3. 2에서 작성한 단어를 가지고, 오늘의 학습 내용을 설명해 보세요.

- React : 프론트엔드 개발을 위한 자바스크립트 라이브러리

▶ 세 가지 특징

  1. 선언형 : 코드를 보고 실제 기능 상상 가능
  2. 컴포넌트 기반 : 각 코드를 기능별로 분리하여 관리 쉬움
  3. 다양한 곳에서 활용 가능 : 어떤 자바스크립트 환경이든 유연하게 사용 가능. 리액트 네이티브로 모바일 개발도 가능.

 

- JSX

React에서 UI를 구성할 때 사용하는 문법으로 JavaScript를 확장한 문법이다. 이 문법을 활용하여 React 엘리먼트를 만들 수 있다.

Babel : JSX를 브라우저가 이해할 수 있는 JavaScript로 컴파일한다.

컴파일 후, JavaScript를 브라우저가 읽고 화면에 렌더링할 수 있다.

React에서는 DOM과 다르게 CSS, JSX 문법만을 가지고 웹 애플리케이션을 개발할 수 있다.

즉, 컴포넌트 하나를 구현하기 위해서 필요한 파일이 줄어들었고, 한눈에 컴포넌트를 확인할 수 있게 되었다.

JSX를 사용하면 JavaScript 만으로 마크업(markup) 형태의 코드를 작성하여 DOM에 배치할 수 있게 되는 것이다.

* 컴포넌트: 구조와 동작에 대한 코드를 한 뭉치로 적은 코드셋

 

- JSX 활용법과 문법

JSX에서 여러 엘리먼트를 작성하고자 하는 경우, 최상위에서 opening tag와 closing tag로 감싸주어야 한다.

React에서 CSS class 속성을 지정하려면 "className"으로 표기해야 한다.

만약 class로 작성하게 된다면 React에서는 이를 html 클래스 속성 대신 자바스크립트 클래스로 받아들이기 때문에 주의해야 한다.

JSX에서 JavaScript를 쓰고자 한다면, 꼭 중괄호를 이용해야 한다. 중괄호를 사용하지 않으면 일반 텍스트로 인식한다.
 

React 엘리먼트가 JSX로 작성되면 "대문자"로 시작해야 한다. 소문자로 시작하게 되면 일반적인 HTML 엘리먼트로 인식한다.

이렇게 대문자로 작성된 JSX 컴포넌트를 따로 사용자 정의 컴포넌트라고 부른다.

조건부 렌더링은 if문이 아닌 삼항연산자를 이용해야 한다.

React 에서 여러 개의 HTML 엘리먼트를 표시할 때는 "map()" 함수를 사용한다.

map 함수를 사용할 때는 반드시 "key" JSX 속성을 넣어야 한다. "key" JSX 속성을 넣지 않으면 리스트의 각 항목에 key를 넣어야 한다는 경고가 표시된다.

 

▶ 예제

const posts = [
  { id: 1, title: "Hello World", content: "Welcome to learning React" },
  { id: 2, title: "Installation", content: "You can install React from npm" }
];

export default function App() {
  // 한 포스트의 정보를 담은 객체 post를 매개변수로 받고
  // obj를 JSX 표현식으로 바꿔 리턴해주는 함수 postToJSX
  const postToJSX = (post) => {
    return (
      <div key={post.id}>
        <h3>{post.title}</h3>
        <p>{post.content}</p>
      </div>
    );
  };

  // TODO: postToJSX 함수를 이용하여 에러를 해결하고 여러 개의 엘리먼트롤 표시해보세요.
  return (
    <div className="App">
      <h1>Hello JSX</h1>
      {posts.map(post => postToJSX(post))}
    </div>
  );
}

출력 결과

- map을 이용한 반복

React에서 여러 데이터를 렌더링 할 때 사용한다.

배열 메서드 map의 특성

  • 배열의 각 요소를
  • 특정 논리(함수)에 의해
  • 다른 요소로 지정(map)합니다.

 

ex) 김코딩의 블로그 포스트 출력하기

const posts = [
    { id : 1, title : 'Hello World', content : 'Welcome to learning React!' },
    { id : 2, title : 'Installation', content : 'You can install React via npm.' },
    { id : 3, title : 'reusable component', content : 'render easy with reusable component.' },
    // ...
    { id : 100, title : 'I just got hired!', content : 'OMG!' },
  ];

function Blog() {
  return (
    <div>
      <div>
         <h3>{posts[0].title}</h3>
         <p>{posts[0].content}</p>
     </div>
      <div>
         <h3>{posts[1].title}</h3>
         <p>{posts[1].content}</p>
      </div>
      {// ...}
      <div>
         <h3>{posts[99].title}</h3>
         <p>{posts[99].content}</p>
      </div>
     {// ... 98 * 4 more lines !!}
   </div>
  );
}

위의 코드를 사용한다면 블로그 포스팅이 늘어날 때마다 매일 코드를 변경해야만 한다.

데이터가 변경될 때마다, 알아서 렌더링할 수는 없을까? React에서는 이런 문제를 해결하기 위해서 배열 메서드 map을 활용한다.

 

function Blog() {
  // postToElement라는 함수로 나누지 않고 아래와 같이 써도 무방합니다.
  const blogs = posts.map((post) => (
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  ));
  return <div className="post-wrapper">{blogs}</div>;
}

key 속성의 위치는 map 메서드 내부에 있는 엘리먼트 즉, 첫 엘리먼트에 넣는다.

 

※ key 속성값이 반드시 id가 되어야 하나요? id가 존재하지 않으면 어떻게 해야 하나요?

key 속성값은 가능하면 데이터에서 제공하는 id를 할당해야 한다. key 속성값은 id와 마찬가지로 변하지 않고, 예상 가능하며, 유일해야 하기 때문이다.

정 고유한 id가 없는 경우에만 배열 인덱스를 넣어서 해결할 수 있다. 배열 인덱스는 최후의 수단(as a last resort)으로만 사용한다.


https://blog.woolta.com/categories/1/posts/210

 

React 에서 배열컴포넌트 사용시 key 에 배열의 index는 가급적 사용하지 말자.!!

woolta 블로그 ver2.0 기술 개발 블로그

blog.woolta.com


- Component

리액트를 이용하면, 각자 독립적인 기능을 가지며 UI의 한 부분을 담당하기도 하는 이러한 컴포넌트를 여러 개 만들고 조합하여 애플리케이션을 만들 수 있다.

모든 리액트 애플리케이션은 최소 한 개의 컴포넌트를 가지고 있으며, 이 컴포넌트는 애플리케이션 내부적으로는 근원(root)이 되는 역할을 한다.

이 최상위 컴포넌트는 근원의 역할을 하므로 다른 자식 컴포넌트를 가질 수 있다. 이 계층적 구조(hierarchy)를 트리 구조로 형상화할 수 있다.

각각의 컴포넌트는 각자 고유의 기능을 가지고 있으면서 UI의 한 부분을 담당하고 있다. 우리는 이렇게 독립적인 컴포넌트들을 여러 개 만들고 이들을 한데 모아 복잡한 UI를 구성할 수도 있고, 더 나아가 최종적으로는 복잡한 애플리케이션도 만들 수 있다.

컴포넌트 기반 개발은 웹 애플리케이션에서 각 기능 별로 하나의 컴포넌트를 작성하도록 권장한다. 그래서 컴포넌트 간 의존성이 낮아지고 독립적으로 작동한다. 하나의 기능 변경 시 다른 컴포넌트를 수정할 필요가 없기 때문이다.

예를 들어, 원하는 수정 사항에 맞추어 컴포넌트의 위치만 수정해 주거나 재사용할 수 있다.


- create-react-app: 단 하나의 명령 만으로 자신만의 리액트 프로젝트를 시작

npx create-react-app@latest 폴더이름

 

- 과제 React twittler Intro 

import React from 'react';
import './App.css';
import './global-style.css';
import { dummyTweets } from './static/dummyData';

// ! 위 코드는 수정하지 않습니다.
console.log(dummyTweets); // 개발 단계에서 사용하는 더미 데이터입니다.

const Sidebar = () => {
  return (
    <section className="sidebar">
      {/* TODO : 메세지 아이콘을 작성합니다. */}
      <i className='far fa-comment-dots'></i>
    </section>
  );
};

const Counter = () => {
  return (
    <div className="tweetForm__input">
      <div className="tweetForm__inputWrapper">
        <div className="tweetForm__count" role="status">
          <div className='tweetForm__count__text' role="status">total: {dummyTweets.length}</div>
        </div>
      </div>
    </div>
  );
};

const Footer = () => {
  return (
    <div>
      {/* <img id="logo" src={`${process.env.PUBLIC_URL}/codestates-logo.png`} /> */}
      <footer>Copyright @ 2022 Code States</footer>
    </div>
  );
};
// TODO : Footer 함수 컴포넌트를 작성합니다. 시멘틱 엘리먼트 footer가 포함되어야 합니다.

const Tweets = () => {
  return (
    <ul className="tweets">
      {dummyTweets.map((tweet) => {
        const isParkHacker = tweet.username === 'parkhacker'
        const tweetUserNameClass = isParkHacker
          ? 'tweet__username tweet__username--purple'
          : 'tweet__username';

        return (
          <li className="tweet" key={tweet.id}>
            <div className="tweet__profile">
              {/* TODO: 트윗 저자의 프로필 사진이 있어야 합니다.  */}
              <img src = {tweet.picture}></img>
            </div>
            <div className="tweet__content">
              <div className="tweet__userInfo">
                {/* TODO : 유져 이름이 있어야 합니다. */}
                <span className={tweetUserNameClass}>{tweet.username}</span>
                {/* TODO : 이름이 "parkhacker"인 경우, 이름 배경색을 rgb(235, 229, 249)으로 바꿔야 합니다. */}
                {/* TODO : 트윗 생성 일자가 있어야 합니다. */}
                <span className='tweet__createdAt'>{tweet.createdAt}</span>
              </div>
              <div className='tweet__message'>{tweet.content}</div>
            </div>
          </li>
        );
      })}
    </ul>
  );
};

const Features = () => {
  return (
    <section className="features">
      <div className="tweetForm__container">
        <div className="tweetForm__wrapper">
          <div className="tweetForm__profile"></div>
          <Counter />
        </div>
      </div>
      <Tweets />
      <Footer />
    </section>
  );
};

const App = () => {
  return (
    <div className="App">
      <h1>My twittler</h1>
      <main>
        {/* TODO : Sidebar 컴포넌트를 작성합니다. */}
        <Sidebar />
        <Features />
      </main>
    </div>
  );
};

// ! 아래 코드는 수정하지 않습니다.
export { App, Sidebar, Counter, Tweets, Features, Footer };

 

반응형