FrontEnd :-)

[항해99] 리액트 기초반 - 2주차 본문

카테고리 없음

[항해99] 리액트 기초반 - 2주차

code10 2022. 5. 20. 22:03

스파르타코딩클럽 #리액트 기초반 2주차

 

[수업 목표]

  1. 컴포넌트의 라이프 사이클을 이해한다.
  2. 컴포넌트의 state를 관리할 수 있다.
  3. 패키지를 찾아서 설치할 수 있다.
  4. React hook을 사용할 수 있다.

2-1. 라이프 사이클이란?  

1) 가상돔이란?

DOM은 html 단위 하나하나를 객체로 생각하는 모델.

DOM 트리 중 하나가 수정될 때마다 모든 DOM을 뒤지고, 수정할 걸 찾고, 싹 수정을 한다면?

→ 필요없는 연산이 너무 많이 일어난다! → 그래서 등장한 게 가상돔!

 

가상돔의 동작 방식:

기존 DOM과 어떤 행동 후 새로 그린 DOM(가상 돔에 올라갔다고 표현합니다)을 비교해서 정말 바뀐 부분만 갈아끼움.

 

2) 라이프 사이클이란?

라이프 사이클(= 컴포넌트 생명주기):

컴포넌트가 렌더링을 준비하는 순간부터, 페이지에서 사라질 때까지

(공식문서) https://ko.reactjs.org/docs/state-and-lifecycle.html

 

State and Lifecycle – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

Lifecyle : Mount / Update / Unmount

  • 수정(업데이트)는 사용자의 행동(클릭, 데이터 입력 등)으로 데이터가 바뀌거나, 부모 컴포넌트가 렌더링할 때 업데이트 됩니다. 아래의 경우죠!
    • props가 바뀔 때 : 부모가 자식에게 주는 데이터 
    • state가 바뀔 때 : 내가 가진 데이터 
    • 부모 컴포넌트가 업데이트 되었을 때(=리렌더링했을 때)
    • 또는, 강제로 업데이트 했을 경우! (forceUpdate()를 통해 강제로 컴포넌트를 업데이트할 수 있습니다.)

2-2.라이프 사이클 함수로 보는 라이프 사이클

라이프 사이클 함수는 클래스형 컴포넌트에서만 사용할 수 있습니다.

리액트 공식 매뉴얼에서 함수형 컴포넌트를 더 권장!

 

 

constructor()

👉 생성자 함수라고도 함. 컴포넌트가 생성되면 가장 처음 호출됨.

render()

👉 컴포넌트의 모양을 정의! 여기에서도 state, props에 접근해서 데이터를 보여줄 수 있음.

render() 안에 들어갈 내용은 컴포넌트의 모양에만 관여하는 것이 가장 좋습니다.

즉, state나 props를 건드려 데이터를 수정하려고 하면 안됩니다!

 

componentDidMount()

👉 컴포넌트가 화면에 나타나는 것을 마운트(Mount)한다고 표현. DidMount()가 첫 렌더링 후에 호출 되는 함수.

didMount() = 마운트 완료. 이 함수는 첫번째 렌더링을 마친 후에만 딱 한 번 실행. 컴포넌트가 리렌더링할 때는 실행되지 않음. 보통은 이 안에서 ajax 요청, 이벤트 등록, 함수 호출 등 작업을 처리. 또, 이미 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됨!

 

componentDidUpdate(prevProps, prevState, snapshot)

👉 DidUpdate()는 리렌더링을 완료한 후 실행되는 함수.

이 함수에 중요한 파라미터가 2개 있는데, prevProps와 prevState입니다. 각각 업데이트 되기 전 props, state예요. 이전 데이터와 비교할 일이 있다면 가져다 쓰기. DidUpdate()가 실행될 때도 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됨!

 

componentWillUnmount()

 👉 컴포넌트가 DOM에서 제거 될 때 실행하는 함수. 만약 우리가 스크롤 위치를 추적 중이거나, 어떤 이벤트 리스너를 등록했다면 여기에서 꼭꼭 해제를 해줘야 함. 컴포넌트 없이 이벤트만 남겨둘 순 없음!

 

🔥 componentWillUnmount()가 호출되는 걸 보려면, app.js에서 <LifecycleEx/>를 없애야 함.

      삼항연산자를 사용해서 컴포넌트를 보여주거나, 없애는 걸 조건부 렌더링이라고 부름. 

2-3. Component (1)

컴포넌트(Component)

=> 웹 사이트의 조각

=> 리액트는 레고, 컴포넌트는 블록

==> 컴포넌트를 이해하고 잘 써먹으려면 웹 사이트를 잘 조각낼 줄 알아야 한다!

=> 종류: 클래스형과 함수형 

==> 이제 클래스형 컴포넌트는 잘 쓰지 않지만, 아직 사용 중인 회사가 많기에 읽고 수정할 정도는 알아야 함.

더보기
  1. <header/>
  2. <container/>
    1. <imagebanner/>
    2. <contents1/>
  3. <footer/>

즉, 이 웹 사이트는, 크게 <header/>, <container/>, <footer/> 세 개의 컴포넌트가 있고,

<container/> 컴포넌트는, <imagebanner/>, <contents1/> 컴포넌트로 이루어져 있다!

웹 사이트를 잘 조각낼 줄 아는 사람 === 리액트를 잘 쓰는 사람

 

State

=> Component가 가지고 있는 데이터

=> 하나의 컴포넌트에서만 사용하는 정보를 주로 넣어놓고 생성, 수정하는 데이터

 

Props

=> Component가 부모 Component로부터 받아온 데이터

=> Props로 받은 데이터는 수정할 수 없다

 

2-4. Component (2)

vscode에서 새 폴더, 새 파일 만들기 

(yarn create react-app bucket_list)

(cd bucket_list)

 

리액트 코딩 룰 1:

폴더명(src, public)은 소문자로 시작

자바스크립트(js) 파일, 컴포넌트 이름은 대문자로 시작(CamelCase)

 

함수형 컴포넌트 

export {BucketList}; 
import {BucketList} from "./BucketList";
 
=
 
export default BucketList;
import BucketList from './BucketList';

2-5. Component (3)

11) 클래스형 Component

import React from 'react';
import logo from './logo.svg';
import './App.css';
// BucketList 컴포넌트를 import 해옵니다.
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from './BucketList';

// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {

  constructor(props){
    super(props);
    // App 컴포넌트의 state를 정의해줍니다.
    this.state = {
      list: ['영화관 가기', '매일 책읽기', '수영 배우기'],
    };
  }

  // 랜더 함수 안에 리액트 엘리먼트를 넣어줍니다!
  render() {
      return (
      <div className="App">
        <h1>내 버킷리스트</h1>
        {/* 컴포넌트를 넣어줍니다. */}
        <BucketList/>
      </div>
    );
  }
}

export default App;

2-6. Quiz_버킷리스트 페이지를 만들어봅시다! 

2-7. 화면을 예쁘게! React에서 CSS 사용하기

(2) CSS 파일을 가져다 쓰려면? import!

import React from 'react';
import logo from './logo.svg';
// BucketList 컴포넌트를 import 해옵니다.
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from './BucketList';
// 이 import를 통해 css 파일을 불러다 씁니다! 
import './style.css';

 

2-8. 화면을 예쁘게! - styled-components

15) styled-components 설치하기

yarn add styled-components

16) styled-components란?

=> CSS-in-JS 라이브러리 중 하나

=> 컴포넌트에 스타일을 직접 입히는 방식

// scss 문법 1: 네스팅! 내가 포함하고 있는 요소에 접근할 수 있어요. ex)내 것{ 자식 것: {}}
// scss 문법 2: &는 나 자신!
const MyStyled = styled.div`
  width: 50vw;
  height: 150px;
  background-color: ${(props) => (props.bg_color ? "red" : "purple")};
  p {
    color: blue;
  }
  &:hover{
    background-color: yellow;
  }
`;

2-9. Quiz_버킷리스트에 styled-components 적용하기

2-10. Ref! 리액트에서 돔요소를 가져오려면?

19) Ref

내가 어떤 인풋박스에서 텍스트를 가져오고 싶으면 어떻게 접근해야할까요? DOM에서 다루는 방법은 1주차에 배웠는데, 리액트에선 어떻게 하면 좋을까요? (render()가 끝나고 가져오면 될까요? 아니면 mount가 끝나고? 아니, 그 전에 가상돔에서 가져오나? 아니면 DOM에서? 😖) → 답은, 리액트 요소에서 가져온다!

 

React 요소를 가지고 오는 방법1 : React.createRef()  // App.js에서

// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
  constructor(props) {
    super(props);
    // App 컴포넌트의 state를 정의해줍니다.
    this.state = {
      list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
    };
    // ref는 이렇게 선언합니다! 
    this.text = React.createRef();
  }

  componentDidMount(){
		// 콘솔에서 확인해보자!
    console.log(this.text);
		console.log(this.text.current);
  }

  // 랜더 함수 안에 리액트 엘리먼트를 넣어줍니다!
  render() {
    
    return (
      <div className="App">
        <Container>
          <Title>내 버킷리스트</Title>
          <Line />
          {/* 컴포넌트를 넣어줍니다. */}
          {/* <컴포넌트 명 [props 명]={넘겨줄 것(리스트, 문자열, 숫자, ...)}/> */}
          <BucketList list={this.state.list} />
        </Container>

        <div>
          <input type="text" ref={this.text}/>
        </div>
      </div>
    );
  }
}

React 요소를 가지고 오는 방법2 : React.useRef() // BuketList.js에서

import React from "react";
import styled from "styled-components";

const BucketList = ({ list }) => {
  const my_lists = list;
  const my_wrap = React.useRef(null);

  console.log(my_wrap); // 콘솔로 확인해봐요!

  window.setTimeout(() => { // 1초 뒤에는?!
    console.log(my_wrap);
  }, 1000);
  return (
    <div ref={my_wrap}>
      {my_lists.map((list, index) => {
        return <ItemStyle key={index}>{list}</ItemStyle>;
      })}
    </div>
  );
};

const ItemStyle = styled.div`
  padding: 16px;
  margin: 8px;
  background-color: aliceblue;
`;

export default BucketList;

2-11. State 관리 (1)

20) 단방향 데이터 흐름이란?

데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다는 소리!

 

21) 클래스형 컴포넌트에서 state 관리 - setState()

라이프 사이클을 볼 때 잠깐 봤던 setState()!

클래스형 컴포넌트의 state를 업데이트할 때 사용하는 함수

 

App.js에서

// App component를 class형으로!
import React from 'react';

class App extends React.Component {

  constructor(props){
    super(props);

    this.state = {
      count: 3
    };
  }

  componentDidMount(){}

  addNemo = () => {
    this.setState({count: this.state.count +1});
  }

  
  removeNemo = () => {
    
    if(this.state.count > 0){
      this.setState({count: this.state.count -1});
    } else{
      window.alert("네모가 없어요!");
    }
  }

  
  render(){
    const nemo_count = Array.from({length: this.state.count}, (v, i) => i);
    console.log(nemo_count);
    console.log(this.state);
    return (
      <div className="App">
        {nemo_count.map((n, i) => {
          return (
            <div 
            key={1}
            style={{
              width: "150px",
              height: "150px",
              backgroundColor: "#ddd",
              margin: "10px"
        }}>
          nemo
        </div>
          )
        })}
      <div>
        <button onClick={() => {
          this.addNemo();
        }}>하나 추가</button>
        <button onClick={() => {
          this.removeNemo();
        }}>하나 빼기</button>
      </div>
        
      </div>
    );
  }
}

export default App;

2-12. State 관리 (2)

Nemo.js 파일을 만들고 시작

(1) Nemo 컴포넌트 만들기

import React from "react";

const Nemo = (props) => {

    // 반환할 리액트 요소가 없을 때는 null을 넘겨주세요! 처음 껍데기 잡으실때도 null을 넘겨주면 굳!
    return null;
}

export default Nemo;

(2) App에서 <Nemo/>불러오기

(3) useState()로 count를 state로 등록하자

// count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
// useState(초기값): () 안에 초기값을 넣어줍니다.
  const [count, setCount] = React.useState(3);

(4) 뷰를 만들고(=반환할 리액트 요소를 만들고),

(5) 함수를 만들어서,

const addNemo = () => {
    // setCount를 통해 count에 저장된 값을 + 1 해줍니다.
    setCount(count + 1);
  };

  const removeNemo = () => {
    // setCount를 통해 count에 저장된 값을 - 1 해줍니다.
    // 이번엔 if문 대신 삼항 연산자로 해볼거예요!
    setCount(count > 0 ? count - 1 : 0);
  };

(6) 연결하자!

        {/* 함수를 호출합니다. */}
        <button onClick={addNemo}>하나 추가</button>
        <button onClick={removeNemo}>하나 빼기</button>
      </div>

2-13. Quiz_버킷리스트에 아이템을 추가해보자! 

import React from "react";
import BucketList from "./BucketList";
import styled from "styled-components";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
    };

    this.text = React.createRef();
  }

  componentDidMount() {  
  }

  addBucket = () => {
    console.log(this.text.current.value);
    const new_item = this.text.current.value;
    // ... => 스프레드 문법
    // [...this.state.list, 넣고 싶었던 어떤 값]
    this.setState({ list: [...this.state.list, new_item] });
  }

  render() {
    
    return (
      <AppWrap className="App">
        <Container>
          <Title>내 버킷리스트</Title>
          <Line />
          <BucketList list={this.state.list} />
        </Container>

        <InputWrap>
          <input type="text" ref={this.text} />
          <button onClick={this.addBucket}>추가하기</button>
        </InputWrap>
      </AppWrap>
    );
  }
}

const AppWrap = styled.div`
  background-color: #eee;
  height: 100vh;
  width: 100vw;
  display: flex;
  flex-direction: column;
`;

const Container = styled.div`
  background-color: #fff;
  width: 50vw;
  max-width: 350px;
  margin: auto;
  height: 80vh;
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 5px;
`;

const Title = styled.h1`
  color: slateblue;
  text-align: center;
`;

const Line = styled.hr`
  margin: 16px 0px;
`;


const InputWrap = styled.div`
  background-color: #fff;
  width: 50vw;
  max-width: 350px;
  margin: auto;
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 5px;
`;

export default App;

 

console.log(this.text) 확인이 어렵네 => console.log(this.text.current.value); 바로 값 확인 가능.

2-14. 

오우 강의를 들어도 '잘 모르겠다'는 느낌뿐.

2-11은 그나마 가장 흥미로웠던 부분ㅋㅋ map함수가 박스 추가에 쓰이는 구나.. 알고리즘 주차때 숫자랑 문자 빼고 더하기만 하다가 박스를 추가하고 빼니까 느낌이 다른, 동시에 자바스크립트 공부 필요성을 다시 한번 강하게 느꼈다. 

Comments