7일차

그루트·2021년 9월 21일
0

라이프 사이클 함수로 보는 라이프 사이클

라이프 사이클 함수는 클래스형 컴포넌트에서만 사용할 수 있습니다.
라이프 사이클을 아는 건 중요한데 왜 우리는 클래스형 컴포넌트보다 함수형 컴포넌트를 많이 쓰냐구요?
리액트 공식 매뉴얼에서 함수형 컴포넌트를 더 권장하기 때문입니다!
(리액트 16.8버전부터 등장한 React Hooks으로 라이프 사이클 함수를 대체할 수 있거든요.)
더 많은 라이프 사이클 함수는 공식 문서에서 확인할 수 있어요 😉

  • 3) constructor()

    생성자 함수라고도 부릅니다. 컴포넌트가 생성되면 가장 처음 호출되는 친구죠!

  • 4) render()

    컴포넌트의 모양을 정의하는 친구입니다!
    여기에서도 state, props에 접근해서 데이터를 보여줄 수 있어요.

    리액트 요소를 return에 넣어 반환해줬던 거 기억하시죠?
    render() 안에 들어갈 내용은 컴포넌트의 모양에만 관여하는 것이 가장 좋습니다.
    즉, state나, props를 건드려 데이터를 수정하려고 하면 안됩니다!

  • 5) componentDidMount()

    컴포넌트가 화면에 나타나는 것을 마운트(Mount)한다고 표현합니다. didMount()는 마운트가 완료 되었다는 소리겠죠?
    이 함수는 첫번째 렌더링을 마친 후에만 딱 한 번 실행됩니다. 컴포넌트가 리렌더링할 때는 실행되지 않아요.
    보통은 이 안에서 ajax 요청, 이벤트 등록, 함수 호출 등 작업을 처리합니다.
    또, 이미 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됩니다!

  • 6) componentDidUpdate(prevProps, prevState, snapshot)

    DidMount()가 첫 렌더링 후에 호출 되는 함수라면, DidUpdate()는 리렌더링을 완료한 후 실행되는 함수입니다.

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

  • 7) componentWillUnmount()

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

Component

Component는 클래스형과 함수형이 있습니다.

이제 클래스형 컴포넌트는 잘 쓰지 않지만, 두 가지를 알아야한다.
→ 왜냐하면 이미 기개발된 프로젝트들(아마 여러분이 가야할 회사에서도...!)은 클래스형 컴포넌트를 사용 중일수도 있거든요. 최소한 코드를 알아보고 고칠 수 있을 정도는 알아두는 편이 좋습니다.

위에서 리액트는 레고라면 컴포넌트는 블록입니다!

  • Component는 웹 사이트의 조각이고, 우리는 이 조각을 모아서 웹사이트에 뿌려준다.

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

State와 Props

State

state는 Component가 가지고 있는 데이터입니다.
  • 헤더에 들어갈 데이터는 뭐가 있을까요?

    → 로고 이미지 경로, 메뉴 이름(온라인, 오프라인, 기업교육, 내 강의실)이 있을 겁니다!

  • 이 데이터는 나

    컴포넌트에서는 쓰지 않겠죠!

  • 즉,

    컴포넌트에서만 쓰는 정보인 셈입니다.

  • state는 한 컴포넌트에서만 사용하는 정보를 주로 넣어놓고 생성, 수정하는 데이터입니다.

  • 생성도 수정도 오직 해당 컴포넌트 내에서만 이뤄집니다. 내꺼니까 생성도 수정도 자유롭죠!

Props

props는 Component가 부모 Component로부터 받아온 데이터입니다.

  • 가 가지고 있는 이미지 경로를 에게 전달해주면, 이 이미지 경로가 컴포넌트의 props가 됩니다.

  • 다시 말해, 부모 컴포넌트로부터 전달 받은 데이터를 props라고 합니다.

  • 그럼 부모 컴포넌트가 가지고 있는 데이터를 컴포넌트가 추가 하거나 수정할 수 있을까요?

    Props로 받은 데이터는 수정할 수 없습니다! 남의 것이니까요!

함수형 Component

리액트 코딩 룰 1:
폴더는 소문자로 시작하는 카멜케이스를 사용
JS파일, 컴포넌트 이름은 대문자로 시작하는 카멜케이스를 사용


// 리액트 패키지를 불러옵니다.
import React from 'react';
// 함수형 컴포넌트는 이렇게 쓸 수도 있고
// function Bucketlist(props){
// return (
//

버킷 리스트

// );
// }

// 이렇게 쓸 수도 있어요. =>가 들어간 함수를 화살표 함수라고 불러요.
// 저희는 앞으로 화살표 함수를 사용할거예요.
// 앗 () 안에 props! 부모 컴포넌트에게 받아온 데이터입니다.
// js 함수가 값을 받아오는 것과 똑같이 받아오네요.
const BucketList = (props) => {

// 컴포넌트가 뿌려줄 ui 요소(리엑트 엘리먼트라고 불러요.)를 반환해줍니다.
return (
    <div>
        버킷 리스트
    </div>
);

}

// 우리가 만든 함수형 컴포넌트를 export 해줍니다.
// export 해주면 다른 컴포넌트에서 BucketList 컴포넌트를 불러다 쓸 수 있어요.
export default BucketList;


그리고 App.js로 돌아가서 BucketList 컴포넌트를 불러와 봅시다.

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

function App() {

  return (
    <div className="App">
      <h1>내 버킷리스트</h1>
      {/* 컴포넌트를 넣어줍니다. */}
      <BucketList/>
    </div>
  );
}

export default App;

  • 이제 크롬으로 돌아가 컴포넌트가 나오는 지 확인해봅시다.


화면을 예쁘게! - styled-components

  • 패키지 설치하기
    터미널에 입력
    yarn add styled-components

styled-components란?

  • class 이름 짓기에서 해방됩니다!

  • 컴포넌트에 스타일을 적기 때문에, 간단하고 직관적입니다!

  • CSS-in-JS 라이브러리 중 하나입니다!
    컴포넌트에 스타일을 직접 입히는 방식이라고 편하게 생각하셔도 됩니다!

사용 방법

먼저 import를 해준다!
import styled from "styled-components";

예)


Ref

그런데 만약에, 내가 어떤 인풋박스에서 텍스트를 가져오고 싶으면 어떻게 접근해야할까요?

(render()가 끝나고 가져오면 될까요? 아니면 mount가 끝나고?
아니, 그 전에 가상돔에서 가져오나? 아니면 DOM에서? 😖)
→ 답은, 리액트 요소에서 가져온다!

React 요소를 가지고 오는 방법1 : React.createRef()


React 요소를 가지고 오는 방법2 : React.useRef()

useRef()는 리액트 훅 중 하나예요. 🙂
리액트 훅은 사용방법이 무지무지 간단합니다!

State 관리

단방향 데이터 흐름이란?

이름에서부터 감이 오지 않나요?
데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다는 소리입니다.

(1) 왜 단방향으로 써야하지?

  • 라이프 사이클과 함께 생각해보기
    부모 컴포넌트의 state가 업데이트 되면 자식 컴포넌트도 리렌더링이 일어납니다.
    만약 자식 컴포넌트의 state가 바뀐 걸 부모 컴포넌트가 props로 받는다고 생각해봅시다.
    그러면 자식 컴포넌트가 업데이트 될 때 부모 컴포넌트도 업데이트 되겠죠?
    앗..., 그럼 또 자식 컴포넌트가 리렌더링 될 거구요. 😢

Class형 컴포넌트

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

라이프 사이클을 볼 때 잠깐 봤던 setState()!
클래스형 컴포넌트의 state를 업데이트할 때 사용하는 함수입니다.

  • (1) 새 CRA 만들기

    yarn create react-app nemo
  • (2) App.js를 class형 컴포넌트로 바꾸고 시작!

    // App component를 class형으로!
    import React from 'react';
    
    class App extends React.Component {
    
      constructor(props){
        super(props);
    
        this.state = {}
      }
    
      componentDidMount(){
    
      }
      
      render(){
    
        return (
          <div className="App">
            
          </div>
        );
      }
    }
    
    export default App;
  • (3) state에 count라는 변수를 추가하고, count 숫자만큼 네모칸을 화면에 띄우기

    • Array.from() 자세히 알아보기→

      import React from "react";
      
      class App extends React.Component {
        constructor(props) {
          super(props);
      
          this.state = {
            count: 3, // 숫자넣기!
          };
        }
      
        componentDidMount() {}
      
        render() {
          // 배열을 만듭니다.
          // Array.from()은 배열을 만들고 초기화까지 해주는 내장 함수입니다.
          // Array.from()의 첫번째 파라미터로 {length: 원하는 길이} 객체를,
          // 두번째 파라미터로 원하는 값을 반환하는 콜백함수를 넘겨주면 끝!
          // array의 내장함수 대부분은 콜백 함수에서 (현재값, index넘버)를 인자로 씁니다.
          const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);
      
          // 콘솔로 만들어진 배열을 확인해봅니다. 숫자가 0부터 순서대로 잘 들어갔나요?
          console.log(nemo_count);
      
          return (
            <div className="App">
              {nemo_count.map((num, idx) => {
                return (
                  <div key={idx}
                    style={{
                      width: "150px",
                      height: "150px",
                      backgroundColor: "#ddd",
                      margin: "10px",
                    }}
                  >
                    nemo
                  </div>
                );
              })}
            </div>
          );
        }
      }
      
      export default App;
  • (4) 더하기, 빼기 버튼을 만들고,

    return (
          <div className="App">
            {nemo_count.map((num, idx) => {
              return (
                <div key={idx}
                  style={{
                    width: "150px",
                    height: "150px",
                    backgroundColor: "#ddd",
                    margin: "10px",
                  }}
                >
                  nemo
                </div>
              );
            })}
    
            <div>
              <button>하나 추가</button>
              <button>하나 빼기</button>
            </div>
          </div>
        );
  • (5) 함수를 만들어서

    	addNemo = () => {
        // this.setState로 count를 하나 더해줍니다!
        this.setState({ count: this.state.count + 1 });
      };
    
      removeNemo = () => {
        // 네모 갯수가 0보다 작을 순 없겠죠! if문으로 조건을 걸어줍시다.
        if (this.state.count > 0) {
          // this.setState로 count를 하나 빼줍니다!
          this.setState({ count: this.state.count - 1 });
        }else{
          window.alert('네모가 없어요!');
        }
      };
  • (6) 연결하자!

    return (
          <div className="App">
            {nemo_count.map((num, idx) => {
              return (
                <div
                  key={idx}
                  style={{
                    width: "150px",
                    height: "150px",
                    backgroundColor: "#ddd",
                    margin: "10px",
                  }}
                >
                  nemo
                </div>
              );
            })}
    
            <div>
              {/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */}
              <button onClick={this.addNemo}>하나 추가</button>
              <button onClick={this.removeNemo}>하나 빼기</button>
            </div>
          </div>
        );
  • (7) 완성본 코드

    • 네모칸 만들기 완성본

      import React from "react";
      
      class App extends React.Component {
        constructor(props) {
          super(props);
      
          this.state = {
            count: 3, // 숫자넣기!
          };
        }
      
        componentDidMount() {}
      
        addNemo = () => {
          // this.setState로 count를 하나 더해줍니다!
          this.setState({ count: this.state.count + 1 });
        };
      
        removeNemo = () => {
          // 네모 갯수가 0보다 작을 순 없겠죠! if문으로 조건을 걸어줍시다.
          if (this.state.count > 0) {
            // this.setState로 count를 하나 빼줍니다!
            this.setState({ count: this.state.count - 1 });
          }else{
            window.alert('네모가 없어요!');
          }
        };
      
        render() {
          // 배열을 만듭니다.
          // Array.from()은 배열을 만들고 초기화까지 해주는 내장 함수입니다.
          // Array.from()의 첫번째 파라미터로 {length: 원하는 길이} 객체를,
          // 두번째 파라미터로 원하는 값을 반환하는 콜백함수를 넘겨주면 끝!
          // array의 내장함수 대부분은 콜백 함수에서 (현재값, index넘버)를 인자로 씁니다.
          const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);
      
          // 콘솔로 만들어진 배열을 확인해봅니다. 숫자가 0부터 순서대로 잘 들어갔나요?
          console.log(nemo_count);
      
          return (
            <div className="App">
              {nemo_count.map((num, idx) => {
                return (
                  <div
                    key={idx}
                    style={{
                      width: "150px",
                      height: "150px",
                      backgroundColor: "#ddd",
                      margin: "10px",
                    }}
                  >
                    nemo
                  </div>
                );
              })}
      
              <div>
                {/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */}
                <button onClick={this.addNemo}>하나 추가</button>
                <button onClick={this.removeNemo}>하나 빼기</button>
              </div>
            </div>
          );
        }
      }
      
      export default App;

함수형 컴포넌트

함수형 컴포넌트에서 state 관리 - useState()

이번에는 함수형 컴포넌트에서 어떻게 state를 쓸 수 있는 지 봅시다.
함수형 컴포넌트는 클래스형처럼 자체적으로 state를 가지고 있지 않지만, react hooks를 사용하면 state를 가질 수 있습니다!

  • (1) Nemo 컴포넌트 만들기

    앞으로 새 함수형 컴포넌트를 만들 때는 파일을 만들고, 함수형 컴포넌트 껍데기까지 만들어주세요! export 잊지 말기! 😉

    import React from "react";
    
    const Nemo = (props) => {
    
        // 반환할 리액트 요소가 없을 때는 null을 넘겨주세요! 처음 껍데기 잡으실때도 null을 넘겨주면 굳!
        return null;
    }
    
    export default Nemo;
  • (2) App에서 불러오기

    // import 먼저 하고
    import Nemo from "./Nemo";
    ...
          <div className="App">
    {/*컴포넌트 불러다 쓰기*/}
            <Nemo/>
         ...
    
    ...
  • (3) useState()로 count를 state로 등록하자

    	// count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
      // useState(초기값): () 안에 초기값을 넣어줍니다.
      const [count, setCount] = React.useState(3);
  • (4) 뷰를 만들고(=반환할 리액트 요소를 만들고),

    const nemo_count = Array.from({ length: count }, (v, i) => i);
      // 반환할 리액트 요소가 없을 때는 null을 넘겨주세요!
      return (
        <div className="App">
          {nemo_count.map((num, idx) => {
            return (
              <div
                key={idx}
                style={{
                  width: "150px",
                  height: "150px",
                  backgroundColor: "#ddd",
                  margin: "10px",
                }}
              >
                nemo
              </div>
            );
          })}
    
          <div>
            <button>하나 추가</button>
            <button>하나 빼기</button>
          </div>
        </div>
      );
  • (5) 함수를 만들어서,

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

    			<div>
            {/* 함수를 호출합니다. */}
            <button onClick={addNemo}>하나 추가</button>
            <button onClick={removeNemo}>하나 빼기</button>
          </div>
  • (7) 완성본 코드

    import React from "react";
    
    const Nemo = (props) => {
      // count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
      // useState(초기값): () 안에 초기값을 넣어줍니다.
      const [count, setCount] = React.useState(3);
    
      const addNemo = () => {
        // setCount를 통해 count에 저장된 값을 + 1 해줍니다.
        setCount(count + 1);
      };
    
      const removeNemo = () => {
        // setCount를 통해 count에 저장된 값을 - 1 해줍니다.
        // 이번엔 if문 대신 삼항 연산자로 해볼거예요!
        setCount(count > 0 ? count - 1 : 0);
      };
    
      const nemo_count = Array.from({ length: count }, (v, i) => i);
      // 반환할 리액트 요소가 없을 때는 null을 넘겨주세요!
      return (
        <div className="App">
          {nemo_count.map((num, idx) => {
            return (
              <div
                key={idx}
                style={{
                  width: "150px",
                  height: "150px",
                  backgroundColor: "#ddd",
                  margin: "10px",
                }}
              >
                nemo
              </div>
            );
          })}
    
          <div>
            {/* 함수를 호출합니다. */}
            <button onClick={addNemo}>하나 추가</button>
            <button onClick={removeNemo}>하나 빼기</button>
          </div>
        </div>
      );
    };
    
    export default Nemo;

정말 중요한 부분입니다. 헷갈리지 않도록 꼭 손에 익혀야해요!
특히 제가 컴포넌트를 만들고→ state를 쓰는 순서! 뷰 먼저→ 그 다음은 state를 만들고(기본값도 잡아주고!)→ state를 조작하는 무언가를 만들어서→연결한다!
이 순서가 중요해요!


오늘은 이상하게 피곤했던거 같다.
반복이 매우 중요해 보인다. 무조건 반복하자..
되새기자 꿈에서도 나올정도로 되새기자

나는 많이 부족하니깐 남들과 같은 시간을 공부하면 안된다.
더 열심히 하자

profile
i'm groot

0개의 댓글