코린이에서 코른이로 ( React State & Props )

양선우·2023년 1월 27일
0

React State & Props 정의

React Component에서 다루는 데이터로 두가지가 있다. 바로 Props 와 State 다.
Props 는 부모 컴포넌트가 자식 컴포넌트에게 주는 값이다. 자식 컴포넌트에서는 Props 를 받아오기만하고,
받아온 Props 를 직접 수정 할 수 는 없다. 이는 한 컴포넌트의 속성(Properties)과 같음을 의미한다.

반면에 State 는 컴포넌트 내부에서 선언하며 내부에서 값을 변경 할 수 있다.
State는 한 컴포넌트 안에서 유동적인 데이터를 다룰 때 사용되며, State는 한 컴포넌트의 상태(State)를 나타냅니다.



예제로 Props의 경우

<div id="name" class="label" onclick="alert('Hello World!');">
  Hello world!
</div>

위의 코드는 HTML의 div 태그에 id와 class 속성을 설정하고 onclick 속성에 직접 자바스크립트의 alert 코드를 사용하였다. 우리는 이미 HTML의 속성이라는 개념을 사용 해 왔었다. React에서는 이 속성 개념에 데이터를 전달한다는 개념을 추가 확장한 것입니다.

const Text = ({text}) => {
  return <div>{text}</div>
}

const App = () => {
  return <Text text='Hello world!'/>
}

위와 같이 부모 컴포넌트(App)에서 자식 컴포넌트(Text)에 속성(Props)을 이용하여 Hello world!라는 문자열 데이터를 전달하는 것을 확인할 수 있다.





예제로 State의 경우

  • 버튼을 누르면, 화면에 표시된 값을 1 증가 시키는 코드다.
import React, { useState } from 'react';

const Text = ({text}) => {
  return <div>{text}</div>
}

const App = () => {
  const [count, setCount] = useState(0);

  return <div>
    <Text text={count} />
    <div onClick={() => setCount(count + 1)}>+</div>
  </div>
}

React의 함수 컴포넌트에서는 State를 사용하기 위해 useState라는 훅(Hook)을 사용해야한다. useState는 State 변수의 초기값을 매개변수로 전달 하여 호출하며, 결과값으로는 배열을 반환하게 된다. 반환된 배열에서는 useState 함수를 호출할 때 설정한 초기값이 할당된 변수와 해당 변수를 수정하기 위한 Set 함수가 포함되어 있다.


const 배열 = useState (데이터 초기값);
배열[0]: 데이터 초기값이 들어간 변수
배열[1]: 데이터를 수정할 수 있는 Set 함수
보통은 반환된 결과값을 자바스크립트의 구조 분해 할당(Destructuring assignment)을 통해 변수와 Set 함수를 할당하여 사용하게 된다.


const [변수명, Set함수명] = useState (데이터 초기값);
useState를 사용하여 할당받은 변수는 불변값(Immutable)이다. 따라서 해당 값은 직접 수정이 불가능하며 해당 값을 변경하기 위해서는 반드시 Set 함수를 사용해야 한다.

const App = () => {
  const [count, setCount] = useState(0);

  return <div>
    <Text text={count} />
    <div onClick={() => setCount(count + 1)}>+</div>
  </div>
}




Twittler 과제

여기까지가 기본적인 State & Props 사용 방법이고 Twittler과제를 진행하면서 만든 코드에 수도코드를 적으며 마치겠다.

Sidebar.js

import React from "react";
// TODO : React Router DOM의 Link 컴포넌트를 import 합니다.
import { Link } from "react-router-dom"; // 링크를 import 해줘야 한다 

const Sidebar = () => {
  return (
    <section className="sidebar">
      {/* TODO : Link 컴포넌트를 작성하고, to 속성을 이용하여 경로(path)를 연결합니다. */}
      <Link to="/"> //Link to 는 Route Path를 쓸때와 같게 쓰면 된다.
        <i className="far fa-comment-dots"></i>
      </Link>
      <Link to="/about">
        <i className="far fa-question-circle"></i>
      </Link>
      <Link to="/mypage">
        <i className="far fa-user"></i>
      </Link>
    </section>
  );
};

export default Sidebar;

Footer.js

import React from "react";

const Footer = () => {
  return <Footer></Footer>;
};
// TODO : Footer 함수 컴포넌트를 작성합니다. 시멘틱 요소 footer가 포함되어야 합니다.

export default Footer;

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 : 유져 이름이 있어야 합니다. */}
            {/* TODO : 트윗 생성 일자가 있어야 합니다. parsedDate를 이용하세요. */}
            <span className="tweet__username">{tweet.username}</span>   ///트윗의 유저 네임
            <span className="tweet__createdAt">{tweet.createdAt}</span> /// 트윗의 생성 일자
          </div>
        </div>
        <div className="tweet__message">{tweet.content}</div> ///트윗박스에 보여질 메시지
      </div>
    </li>
  );
};

export default Tweet;

MyPage.js

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.fillter((tweet) => {
    return tweet.username == "parkhacker"; // 필터를 사용하여 유저네임이 parkhacker 만 보여주게끔
  });
  // TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다.

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

export default MyPage;

Twwets.js

// TODO : useState를 react로 부터 import 합니다.
import React /* TODO */ from "react";
import Footer from "../Footer";
import Tweet from "../Components/Tweet";
import "./Tweets.css";
import dummyTweets from "../static/dummyData";

const Tweets = () => {
  // TODO : 새로 트윗을 작성하고 전송할 수 있게 useState를 적절히 활용하세요.

  const getRandomNumber = (min, max) => {
    return parseInt(Math.random() * (Number(max) - Number(min) + 2));
  }; // 더미데이터의 값을 그대로 가져왔다

  const [user, setUser] = useState("parkhacker");
  const [msg, setMsg] = useState("");
  const [tweets, setTweets] = useState(dummyTweets);

  const handleButtonClick = (event) => {
    const tweet = {
      id: dummyTweets.length,
      username: user,
      picture: `https://randomuser.me/api/portraits/women/${getRandomNumber(
        1,
        98
      )}.jpg`,
      content: msg,
      createdAt: new Date().toLocaleDateString("ko-kr"),
      updatedAt: new Date().toLocaleDateString("ko-kr"),
    };
    // TODO : Tweet button 엘리먼트 클릭시 작동하는 함수를 완성하세요.
    // 트윗 전송이 가능하게 작성해야 합니다.
    setTweets([tweet, ...tweets]); // tweet이 tweets 에 갱신되게끔
  };

  const handleChangeUser = (event) => {
    // TODO : Tweet input 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
    setUser(event.target.value); // 작동하게끔 함수 설정
  };

  const handleChangeMsg = (event) => {
    // TODO : Tweet textarea 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
    setMsg(event.target.value); // 작동하게끔 함수 설정
  };

  return (
    <React.Fragment>
      <div className="tweetForm__container">
        <div className="tweetForm__wrapper">
          <div className="tweetForm__profile">
            <img src="https://randomuser.me/api/portraits/men/98.jpg" />
          </div>
          <div className="tweetForm__inputContainer">
            <div className="tweetForm__inputWrapper">
              <div className="tweetForm__input">
                <input
                  type="text"
                  defaultValue="parkhacker"
                  value={user}
                  placeholder="your username here.."
                  className="tweetForm__input--username"
                  onChange={handleChangeUser}
                ></input>
                TODO : 트윗을 작성할 수 있는 textarea 엘리먼트를 작성하세요.
                <textarea //위에 인풋을 보면서 구상하였다.
                  defaultValue="" // 기본적으로 보여지는 값은 빈칸
                  value={msg} // 값으로 들어오는것은 msg
                  ClassName="tweetForm__input--message"
                  placeholder="your message here.." 
                  onChange={handleChangeMsg} // 이벤트함수를 걸어주었다.
                ></textarea>
              </div>
              <div className="tweetForm__count" role="status">
                <span className="tweetForm__count__text">
                  {/* TODO : 트윗 총 개수를 보여줄 수 있는 Counter를 작성하세요. */}
                  {"total: " + tweets.length} // tweets의 길이만큼
                </span>
              </div>
            </div>
            <div className="tweetForm__submit">
              <div className="tweetForm__submitIcon"></div>
              {/* TODO : 작성한 트윗을 전송할 수 있는 button 엘리먼트를 작성하세요. */}
              <button
                className="tweetForm__submitButton"
                onClick={handleButtonClick}// 결과버튼으로 갱신되게끔 함수를 넣어주었다
              >
                Tweet
              </button>
            </div>
          </div>
        </div>
      </div>
      <div className="tweet__selectUser"></div>
      <ul className="tweets">
        {/* TODO : 하나의 트윗이 아니라, 주어진 트윗 목록(dummyTweets) 갯수에 맞게 보여줘야 합니다. */}
        {tweets.map((el) => {
          return <Tweet tweet={el} />; // 갯수에 맞게 보여줘야해서 map을 사용하였다.
        })}
      </ul>
      <Footer />
    </React.Fragment>
  );
};

export default Tweets;
profile
코딩이 하고 싶은 사람

0개의 댓글