S2 Unit6 - React State & Props

딩쓰·2022년 10월 1일

코드스테이츠 TIL

목록 보기
7/19

Before You Learn..

Unit4에서 배운것: React에서 컴포넌트 기반으로 화면을 구성하는 방법
Unit5에서 배운것: 라우팅을 통해 경로에 따라 다른 뷰를 보여주는 방법

학습 목표

  • state, props의 개념에 대해서 이해하고, 실제 프로젝트에 바르게 적용할 수 있음
  • React 함수 컴포넌트에서 state hook을 이용하여 state를 정의 및 변경할 수 있음
  • React 컴포넌트에 props를 전달할 수 있음
  • 이벤트 핸들러 함수를 만들고 React에서 이용할 수 있음
  • 실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 state이고 props에 적합한지 판단할 수 있음
  • 실제 웹 애플리케이션 개발 시 적합한 state와 props의 위치를 스스로 정할 수 있음
  • React의 단방향 데이터 흐름에 대해 자신의 언어로 설명할 수 있음

Props

외부로부터 전달받은 바꿀 수 없는 값
ex) 이름, 성별

  • 컴포넌트의 속성(property)을 의미
  • 부모(상위) 컴포넌트로부터 전달받은 값
    • 컴포넌트가 렌더링 될 때 , 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용 가능
  • 객체 형태
    • 어떤 타입의 값도 전달 가능하도록 객체 형태를 가짐
  • 읽기 전용: 외부로부터 전달받아 변경불가 읽기 전용 객체
    • 읽기 전용 객체가 아니면
      props 전달받은 하위 컴포넌트에서 props 수정 시 상위 컴포넌트의 값에 영향을 주기 때문임. 그러면 side effect가 생기게 됨
  • immutable 불변성한 데이터

props 사용법

1.하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의
2.props를 이용하여 정의된 값과 속성을 전달
3.전달받은 props를 렌더링

//Parent와 Child라는 컴포넌트를 선언하고 Parent안에 Child 컴포넌트 작성
function Parent() { 
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child text={"I'm the eldest child"} />  
    </div>
//text라는 속성을 선언하고 Child 컴포넌트에 전달하려는 값에 중괄호{}를 이용*
  );
}

//함수에 인자를 전달하듯이 props를 전달받음(모든 데이터 가져옴)
function Child(props) {   
  return (
    <div className="child">
      <p>{props.text}</p>
    </div>
//props를 전달받고 렌더링하기 -> JS에서 객체의 값에 접근하는 dot notation방법으로 props.text를 작성
  );
}

export default Parent;
  • 부모 컴포넌트에서 <Child attribute={value} />로 속성을 넣고 function Child(props) 로 props를 받는다

-렌더링된 화면

State

  • 컴포넌트 내부에서 변할 수 있는 값 ex)나이,현재 사는 곳,결혼/연애 여부
  • 변하는 값
    • Toggle Switch: On/Off 여부
    • Counter: 숫자 값 증감
    • 쇼핑몰 장바구니: 체크 여부에 따라 구매할 물건의 개수나 금액이 변경
  • React에서는 state 를 다루는 함수를 제공 useState

State hook, useState

useState 사용법

  • 체크박스로 든 예시
//useState 를 이용하려면 import 키워드로 useState 를 불러와야 함
import React, { useState } from "react";

function CheckboxExample() {
//이후 useState 를 컴포넌트 안에서 호출해 줌 
//useState 호출 = "state" 라는 변수를 선언하는 것(변수 이름 아무거나 가능. 여기선 isChecked)
//useState를 호출하면 배열을 반환 
//배열의 0번째는 state 변수, 1번째는 이 변수를 갱신할 수 있는 함수
//useState 의 인자로 넘겨주는 값은 state의 초깃값(useState(false))  
  const [isChecked, setIsChecked] = useState(false);
//const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
  
  const handleChecked = (event) => {
    setIsChecked(event.target.checked);
  };
//state를 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked 를 호출
  return (
    <div className="App">
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
//state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 불러서 사용
//여기서 isChecked는 boolean 값이라서 삼항연산자를 사용
    </div>
//유저가 체크박스 값을 변경하면 onChange가 이벤트 핸들러 함수인 handleChecked 를 호출
//이 함수가 setIsChecked 를 호출하게 됨
//호출된 결과에 따라 isChecked 변수가 갱신
//React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨
//해당 컴포넌트를 다시 렌더링
  );
}

export default CheckboxExample;
  • const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);

state hook 사용 시 주의점

  • React 컴포넌트는 state가 변경되면 새롭게 호출되고, 리렌더링 됨
  • React state는 상태 변경 함수 호출로 변경해야 함
    • 강제로 변경하면, 리렌더링X or state가 제대로 변경되지 않음

과제 React Twittler State & Props

//Tweet.js
import React from 'react';
import './Tweet.css';

const Tweet = ({ tweet }) => {
  const parsedDate = new Date(tweet.createdAt).toLocaleDateString('ko-kr');

  return (
    <li className="tweet" id={tweet.id}>
      <div className="tweet__profile">
        <img src={tweet.picture} />
      </div>
      <div className="tweet__content">
        <div className="tweet__userInfo">
          <div className="tweet__userInfo--wrapper">
            {/* TODO : 유져 이름이 있어야 합니다. */}
            <span className="tweet__username">{tweet.username}</span>
            {/* TODO : 트윗 생성 일자가 있어야 합니다. parsedDate를 이용하세요. */}
            <span className="tweet__createdAt">{parsedDate}</span>
          </div>
        </div>
        <div className="tweet__message">
          {tweet.content}
        </div>
      </div>
    </li>
  );
};

export default Tweet;
//MyPage
import React from 'react';
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './MyPage.css';
import dummyTweets from '../static/dummyData';

const MyPage = () => {
  const filteredTweets = dummyTweets.filter(el => {return el.username === 'parkhacker' })
  // TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다.

  return (
    <section className="myInfo">
      <div className="myInfo__container">
        <div className="myInfo__wrapper">
          <div className="myInfo__profile">
            <img src={filteredTweets[0].picture} />
          </div>
          <div className="myInfo__detail">
            <p className="myInfo__detailName">
              {filteredTweets[0].username} Profile
            </p>
            <p>28 팔로워 100 팔로잉</p>
          </div>
        </div>
      </div>
      <ul className="tweets__mypage">
        { 
          filteredTweets.map(el => {
            return <Tweet tweet={el}/> 
          })
        }
        
        {/* TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다. */}
      </ul>
      <Footer />
    </section>
  );
};

export default MyPage;
//App.js
import React from 'react';
import {BrowserRouter, Routes, Route} from "react-router-dom"
// TODO : React Router DOM을 설치 후, import 구문을 이용하여 BrowserRouter, Routes, Route 컴포넌트를 불러옵니다.

import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import About  from './Pages/About';
import MyPage from './Pages/MyPage';
// TODO : MyPage, About 컴포넌트를 import 합니다.

import './App.css';
import './global-style.css';

const App = (props) => {
  return (
    <BrowserRouter>
    <div className="App">
      <main>
        <Sidebar />
        <section className="features">
          {/* TODO : 유어클래스를 참고해서, 테스트 케이스를 통과하세요.
            TODO : React Router DOM 설치 후 BrowserRouter, Routes, Route의 주석을 해제하고 Routes, Route 컴포넌트를 적절하게 작성합니다. */}
          {/* Route 예시: <Route path="/" element={<Tweets />}></Route> */}
        </section>
      </main>
      <Routes>
         <Route path="/" element={<Tweets />}></Route>
         <Route path="/about" element={<About />}></Route>
         <Route path="/mypage" element={<MyPage />}></Route>
      </Routes>
    </div>
    </BrowserRouter>
  );
};

// ! 아래 코드는 수정하지 않습니다.
export default App;
//Sidebar.js
import React from 'react';
import { Link } from 'react-router-dom';

// TODO : React Router DOM의 Link 컴포넌트를 import 합니다.

const Sidebar = () => {
  return (
    <section className="sidebar">
      {/* TODO : Link 컴포넌트를 작성하고, to 속성을 이용하여 경로(path)를 연결합니다. */}
      <Link to='/'><i className="far fa-comment-dots"></i></Link>         {/*Tweets 메뉴 아이콘*/}
      <Link to='/about'><i className="far fa-question-circle"></i></Link> {/*About 메뉴 아이콘*/}
      <Link to='/mypage'><i className="far fa-user"></i></Link>           {/*MyPage 메뉴 아이콘*/}
    </section>
  );
};

export default Sidebar;

profile
Frontend Developer

0개의 댓글