[Sprint #7-2] React - React Core Concept (1)

홍영란·2020년 1월 20일
0

Reference

React | 생활코딩
Virtual DOM | velopert
리액트 초심자를 위한 핵심 강좌 | velopert
Virtual DOM in simple English
Function component vs. Class component
Stateless component vs. Stateful component
Complete Intro React
React Basics: State, Props & Functional Components


image.png


Sprint

𝖨. Start React

⭐︎React 공식문서: React 12 main concepts
⭐︎React 공식문서: Practical Tutorial
React 공식문서(한국어)
React 공식문서 번역

※ JavaScript Tutorial
JavaScript
Modern.js


React ?

  • Facebook에서 만든 JavaScript UI 라이브러리
  • Why React ?
    • 언어의 구조가 사람의 생각 구조에 가깝게 직관적(Declarative)
    • 재사용 가능한 컴포넌트(Reusable components)

⭐︎ React 주요 개념

1. JSX

const element = <h1>Hello, world!</h1>;

: (HTML과 비슷해 보이지만) JavaScript의 확장 문법

  • JSX는 React "elements" 생성: DOM에 render
  • Why JSX?
    => 복잡도 감소, 가독성 증가
  • JSX은 Babel을 통해 transpile 됨

JSX 규칙

1) 반드시 하나의 element로 감싸야 한다.

<div>
  <div>
    <h1>React</h1>
  </div>
  <div>
    <h2>JSX</h2>
  </div>
</div>

2) 자바스크립트 코드를 적용할 땐, {}(중괄호) 안에 작성

const name = 'Miranda Hart';
const element = <h1>Hello, {name}</h1>;

3) JSX 내부에선 if문 사용 불가 —> IIFE or 삼항 연산자 사용

<div>
  {
  (1 + 1 === 2) ? (<h1>정답</h1>) : (<h1>오답</h1>)
  }
</div>

4) element의 클래스 이름 => className 사용

// ES6
<div class="app-container">App</div>
// JSX
<div className="app-container">App</div>

JSX에 표현식 포함

const name = 'Miranda Hart';
const element = <h1>Hello, {name}</h1>;
// name이라는 변수를 선언한 후 중괄호로 감싸 JSX 안에 사용
ReactDOM.render(
  element,
  document.getElementById('root')
);
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}
const user = {
  firstName: 'Miranda',
  lastName: 'Hart'
};
// JS 함수 호출의 결과인 formatName(user)을 <h1> 엘리먼트에 포함
// * 2) 자바스크립트 코드를 적용할 땐, __{}(중괄호)__ 안에 작성
const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);
// Split JSX over multiple lines for readability
// Recommend wrapping it in parentheses to avoid "automatic semicolon insertion".
// (ref: https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi)
ReactDOM.render(
  element,
  document.getElementById('root')
);
// Hello, Miranda Hart!

JSX도 표현식

  • 컴파일이 끝나면, JSX 표현식이 "정규 JS 함수 호출"이 되고 JS 객체로 인식
    • If구문 및 for loop 안에서 사용 가능
    • 변수에 할당하는 것(assign it to variables) 가능
    • 전달인자(arguments)로 받는 것 가능
    • 함수로부터 반환하는 것(return it from functions) 가능
function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger:)</h1>;
}

JSX 속성 정의

  • 따옴표를 이용해 속성에 문자열 리터럴 을 정의
  • 중괄호를 사용하여 속성에 JavaScript 표현식 을 삽입
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;

JSX는 객체를 표현

// 다음 두 예시는 동일
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
// JSX는 Babel을 통해 React.createElement() 호출로 컴파일
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
  • 생성된 객체 => “React elements”(화면에 표시하려는 항목에 대한 설명)
// Note: 구조 단순화
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

※ ES6 및 JSX 코드가 올바르게 표시되도록 편집기에 Babel 언어 설정 사용하는 것을 권장


2. Element

: React 앱의 가장 작은 단위; 화면에 표시할 내용을 기술

  • React Element일반 객체이며(plain object) 쉽게 생성 가능
  • React DOM은 React 엘리먼트와 일치하도록 DOM을 업데이트

Element를 DOM Element로 랜더링

  • ReactDOM.render()id 'root'을 가진 'div' 요소에 앱 컴포넌트를 랜더
  • 랜더링 하려면 ReactDOM.render()로 1) React Element 2) root DOM Node 전달
//  root DOM Node
<div id="root"></div>
// To render a React element into a root DOM node, pass it to ReactDOM.render
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

Rendered Element를 업데이트 하기

  • React elements는 "immutable"(불변 객체)
    • element는 한번 생성되면, 그 children이나 attributes(속성) 바꿀 수 없다.
  • UI를 업데이트(랜더링 된 출력값 변경)하는 유일한 방법
    • 새로운 element 생성하고, ReactDOM.render()로 전달하는 것.
function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
// 위 함수는 setInterval() 콜백을 이용해 1초마다 ReactDOM.render()를 호출
// Hello, world!
// It is 오후 8:13:22.(현재 시간)
// 내용이 변경된 텍스트 노드만 업데이트
  • React DOM은 해당 element와 그 children element를 이전의 element와 비교
    • DOM을 원하는 상태로 만드는데 '필요한 경우에만' DOM을 업데이트

react-component vs.element


3. Component

Detailed component API
: 하나의 의미를 가진 독립적인 단위 모듈 (쉽게 말해 나만의 HTML 태그)

Components are the building blocks of a React application. They are reusable and independent blocks of code.

A Component is a function or a Class which optionally accepts input and returns a React element
Element & Component

  • Why Component?
    => 직관적 코드, 재사용성 증가

1) Function(a.k.a. Stateless, Container) Component

// 데이터를 가진 하나의 “props” (props는 속성을 나타내는 데이터) 객체 인자를 받은 후 React 엘리먼트를 반환하는 유효한 React 컴포넌트
// * 함수 컴포넌트; JavaScript 함수
const myComponent => (props) {
  return (
    <elementOrComponent../>
    );
  }
// return JSX

스크린샷 2020-01-20 오후 9.08.57.png

2) (ES6) Class(a.k.a Stateful, Presentational) Component

// * 클래스 컴포넌트; ES6 Class
class myComponent extends React.Component {
  render() {
    return ( 
      <elementOrComponent../>
      );
   }
}
// return JSX
  • Class 컴포넌트return 구문으로 이루어진 'render' 메소드를 포함한다.
    • return 구문 안에 있는 모든 것은 브라우저에서 render 된다.

스크린샷 2020-01-20 오후 9.09.06.png

This private internal state is what gives React its reactive nature. When the state of a class component changes, React will re-render that component in the browser.
(ref: https://medium.com/edge-coders/how-to-write-your-first-react-js-component-d728d759cabc)

Functional Component vs. Class Component

ComponentFucntionalClass
장점(비교적)빠르다/재사용성/디버깅이 쉽다state, lifecycle API 사용 가능, (React.Component로부터 상속받음)
단점state, lifecycle API 사용 불가간결성 떨어진다

React Component 생성

  • React Component 이름은 항상 대문자
    => JSX에서 소문자 태그 이름은 HTML 태그로 간주
    JS React playground(to test JavaScript & React code in the browser w/o install)
// * JSX
// Define a new function that returns an HTML button element
// button element in JSX will be compiled into JavaScript
function Button() {
  return (
    <button>Go</button>
  );
}
// * actual javascript
// React.createElement function
function Button() {
  return (
    React.createElement("button", null, "Go")
  );
}

Component 랜더링

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// * 컴포넌트의 이름은 항상 대문자로 시작 (<Welcome />)
// 1. <Welcome name="Miranda" /> 엘리먼트로 ReactDOM.render()를 호출
// 2. React는 {name: "Miranda" }를 props로 하여 Welcome 컴포넌트를 호출
// 3. Welcome 컴포넌트는 결과적으로 <h1>Hello, Miranda</h1> 엘리먼트를 반환
// 4. React DOM은 <h1>Hello, Miranda</h1> 엘리먼트와 일치하도록 DOM을 업데이트
const element = <Welcome name="Miranda" />;
ReactDOM.render(
  element,
  document.getElementById('root')
// > "Hello, Miranda"
);

Component 합성

  • 컴포넌트는 자신의 output에 다른 컴포넌트를 refer(참조)
// Welcome을 여러 번 렌더링하는 App Component
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Miranda" />
      <Welcome name="Stevie" />
      <Welcome name="Fanny" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

// > Hello, Miranda
// > Hello, Stevie
// > Hello, Fanny

Component 추출

※ 참고: extracting-components

  • 컴포넌트를 여러 개의 작은 컴포넌트로 나누어 "재사용" 가능한 컴포넌트로 만드는 것

4. Props

: 상위 컴포넌트하위 컴포넌트에게 내려주는 properties(속성)데이터

  • 하위 컴포넌트는
    • 단순히 사용만 할 수 있다.
    • 변경할 수 없다.
// 상위 컴포넌트(부모)
function Parent() {
  return (
    // 사용자 정의 컴포넌트
    <Child name = "Amy" />
    )
}
// 하위 컴포넌트(자식)
function Child(props) {
  return (
    <h1>Hello, {props.name}</h1>;
    )
}
// 상위 컴포넌트(부모)
class App extends React.Component {
 render() {
   // 사용자 정의 컴포넌트
  return <Child value="SOS" />;  
 }
}
// 하위 컴포넌트(자식)
class Child extends React.Component{
 render(){
  return <h3>The value passed from parent is {this.props.value}</h3>;
 }
}
  • Props Name: 상위 컴포넌트에서 넘겨줄 때 사용한 이름 (ex) "Amy", "SOS")

5. State

: 컴포넌트가 갖는 상태; 객체의 형태로 컴포넌트 내에서 보관하고 관리

State is similar to props, but it is private and fully controlled by the component.

1) Class 컴포넌트로 작성되어야 한다.
2) 값을 변경할 때 반드시 setState 메서드를 사용해야 한다.
3) 값이 변경되면, render() 함수가 실행된다.

Props(속성) vs. State(상태)

구분PropsState
일반 JavaScript 객체일반 JavaScript 객체
고정 값(Immutable)변화 가능(Mutable) => setState
컴포넌트에 전달(함수 매개변수)컴포넌트 안에서 관리(함수 내 선언 변수)
부모(상위) 컴포넌트 데이터를 포함컴포넌트의 로컬 데이터를 포함(캡슐화)
읽기 전용(read-only)읽거나(readable), 쓰는 것(writable) 가능
비동기적(Asynchronous) 변화 가능

SetState()

※ 참고: using-state-correctly

  • setState()는 컴포넌트의 state 객체에 대한 업데이트를 실행.
    • state가 변경되면, 컴포넌트는 리렌더링
  1. 직접 State를 수정하면 안된다.
// Wrong
this.state.comment = 'Hello';
// 대신에 setState()를 사용
// Correct
this.setState({comment: 'Hello'});
// this.state를 지정할 수 있는 유일한 공간은 바로 constructor
  1. State 업데이트는 비동기적일 수도 있다.
  • this.props와 this.state가 비동기적으로 업데이트될 수 있기 때문에 다음 state를 계산할 때 해당 값 고정되어 있지 않다.
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
// * 객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용
// 이전 state를 첫 번째 인자로, 업데이트가 적용된 시점의 props를 두 번째 인자로 받는 함수
  1. State 업데이트는 병합(Merge)된다.
  • setState()를 호출할 때 React는 제공한 객체를 현재 state로 병합
constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }
// 별도의 setState() 호출로 이러한 변수를 독립적으로 업데이트
componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

⭐️ 하위 component에서 상위 component 데이터 변경하는 법

class App extends React.Component {
 constructor(){
  super();
  this.state = {name :"Miranda Hart"};
 }
 changeName(){
  this.setState({name : "Stevie Sutton"});
 }

 render(){
  return (
   <div>
     <h3>Hello {this.state.name}</h3>
     <button type='button' onClick=this.changeName.bind(this)}>
      Save
     </button>
   </div>
  );
 }
}
// setState에 매개변수로 객체 전달
// React는 비동기적으로 state에 변화 만든다.
// (전달된 객체의 key값만을 제시된 value 값으로 바꾼다)
// (ref: https://dev.to/blizzerand/react-basics--state-props--functional-components-5cll)
profile
JavaScript를 공부하고 있습니다:)

0개의 댓글