[TIL] Udemy 31일차 프론트엔드/백엔드 - React 실습

강준호·2024년 1월 29일

Udemy

목록 보기
36/44
post-thumbnail

리액트 기초 익히기

npm ?

  • npm (Node Package Manager)은 Node.js의 패키지 관리자로, JavaScript 라이브러리와 응용 프로그램을 공유하고 관리하는 플랫폼이에요. npm을 통해 필요한 라이브러리를 쉽게 설치하고 관리할 수 있어요.

  • package 의 의존성을 관리 + 버전 정보 기록

npx ?

  • npx는 node.js를 위한 패키지 실행도구

  • node를 설치하면 npm과 함께 설치

  • npx를 사용하면 컴퓨터에 설치하지 않은 npm 패키지를 실행할 수 있고, 프로젝트에 설치된 패키지도 쉽게 실행할 수 있다


React Component와 React Element의 차이

리액트 컴포넌트 (React Component)

  • 리액트 컴포넌트는 UI의 한 부분을 캡슐화한 코드 블록이에요.
  • 과거에는 클래스를 사용하여 컴포넌트를 만들었지만 이제는 함수로 만드는 것이 보편화되었다.
function Greeting() {
	return <div>Hello World</div>
}

리액트 엘리먼트 (React Element)

  • 리액트 엘리먼트는 컴포넌트의 인스턴스로, 화면에 표시할 내용을 기술한 객체.
  • JSX 문법을 사용하여 생성할 수 있다
<Greeting />

React 프로젝트 생성하기

  • CRA를 사용한 React 프로젝트는 아래 명령어로 생성할 수 있어요
    npx create-react-app 원하는프로젝트명
  • React 어플리케이션 개발을 시작할 수 있는 템플릿과 필요한 라이브러리들을 자동으로 설치

  • node_modules: npm으로 설치한 패키지들이 저장되어 있는 디렉터리에요.
  • public: 우리 웹서비스의 루트 경로(/)에서 바로 접근 가능한 에셋들을 담아 두는 디렉터리에요.
  • src: 우리 웹서비스의 주요 소스 코드들을 저장하고 관리하는 디렉터리에요.
    • App.js: 프로젝트의 루트 컴포넌트에요.
    • App.css: 루트 컴포넌트에서 사용할 스타일들을 담아 둔 스타일시트 파일이에요.
    • index.css: 프로젝트 전반에 걸쳐 사용할 스타일들을 담아 둔 스타일시트 파일이에요.
    • index.js: 루트 컴포넌트를 HTML document에 연결시켜주는 코드가 들어 있는 JS 파일이에요
  • package.json: 프로젝트의 주요 정보들을(이름, 설치된 패키지, 스크립트 등) 담고 있는 파일이에요.
  • package-lock.json: package.json을 통해 설치된 패키지들의 상세 정보들을 담고 있는 파일이에요

+ 컴포넌트는 대문자로 시작!

rfce => 리액트 컴포넌트 만들기 키워드


props(데이터 흐름 만들기)

  • 부모 컴포넌트로부터 자식 컴포넌트에 전달하는 데이터를 Props

  • 자식 컴포넌트 입장에서 Props는 읽기 전용으로, 수정불가

  • props를 잘 사용하면 컴포넌트의 재사용성과 유연성이 크게 증가해요.

  • 부모가 전달해 주는 props 값이 바뀌면 자식 컴포넌트는 리렌더링을 해요.

function Greeting(props) {
  return <h1>안녕하세요, {props.name}!</h1>;
}

function App() {
	const someName = "철수"
  return (
    <div>
      <Greeting name="지수" />
      <Greeting name={someName} />
    </div>
	);
}

children : 특별한 props

  • 리액트에는 children이라는 특별한 props가 존재
  • 컴포넌트로 여는 태그와 닫는 태그를 만든 뒤 그 사이에 값을 넣으면, 그 값은 해당 컴포넌트에 children 이라는 이름의 props로 전달된다.
<Display>ㅎㅇ</Display>
  • 이렇게 쓰는건 칠드런.
  • 칠드런은 안에서 받아줘야한다. 함수에 인자를 넣는것처럼 props로.

props

숫자라던가 텍스트가 아닌 다른값을 props 로 넘길때에는

 <Display number={5} />

함수는 handleClick 이렇게 동사형태로 명칭짓기


input 은 onChange
button 은 onClick

둘다 안에 이벤트 객체가 들어있고 반환해.


State

  • 컴포넌트의 기억공간( 현재 입력되고 있는 값 or 이미지 등등 기억을 보관해야하기때문)

  • State가 바뀌면 컴포넌트는 리렌더링을 한다.

  • 함수가 재실행된다(= 리렌더링 된다) => 화면 다시 렌더링

  • 함수는 재실행되지만 상태값은 초기화가 되지않고 어딘가에 계속 기억이 되고 있다.

기억이 보이게 바뀌려면 리렌더링 되어야한다! => 함수가 재실행되어야한다.

  • 함수가 재실행되지 않으면 다시 그려지지 않아 => State의 필요!

카운터 만들기

const [count, setCount] = useState();
  • 구조 분해로 바로 받기.

  • 그냥 근데 count 를 바꿀 수 없어. => const 기 때문.

  • setCount(count +1)로 바꿔

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

  const handleClickButton = () => {
    setCount(count + 1);
  • useState(0) 처럼 초기화해줘야해.

TIP) use 라는 이름이 붙으면 리액트에서는 훅이라고 부름

setCount((prevCount) => prevCount + 1);
  • 직전 값에 의존해야하는 경우 이렇게 콜백함수를 사용해야 안전하다.
  • prevCount 는 이전값을 받아오는거기때매 더 안전!

전체 코드

import React, { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  const [gap, setGap] = useState(1);

  console.log();

  const handleClickMinus = () => {
    setCount(count - gap);
  };
  const handleClickPlus = () => {
    setCount(count + gap);
  };

  return (
    <div>
      <h2>카운터</h2>
      <div>현재 숫자: {count}</div>

      <input
        type="number"
        value={String(gap)}
        onChange={(e) => {
          setGap(Number(e.target.value));
        }}
      />
      <div>
        <button onClick={handleClickMinus}>-</button>
        <button onClick={handleClickPlus}>+</button>
      </div>
    </div>
  );
}

export default Counter;

색상 선택기 만들기

      <button onClick={handleClickColor("red")}>빨강</button>
        <button onClick={handleClickColor("orange")}>주황</button>
        <button onClick={() => handleClickColor("yellow")}>노랑</button> x
        <button onClick={() => handleClickColor("green")}>초록</button> x
        <button onClick={() => handleClickColor("indigo")}>군청</button>x
        


  const handleClickColor = (color) => {
    return () => setSelectedColor(color);
  };

onClick 에는 함수가 들어가야해. 근데 화살표 함수 없이 그냥 쓰면 바로 handleClickCOlor 를 호출 하니까 안돼.

  • 위 함수로 묶어서 반환하면 해결!

전체 코드

import React, { useState } from "react";

function ColorSelector() {
  const [selectedColor, setSelectedColor] = useState("black");

  const handleClickColor = (color) => {
    setSelectedColor(color);
  };

  return (
    <div>
      <h2>색상선택기</h2>

      <div
        style={{
          backgroundColor: selectedColor,
          width: 100,
          height: 100,
          margin: "0 auto",
        }}
      ></div>

      <div>
        {/* 바로호출되니까 이를 방지하기 위해 화살표 함수로 감싸 */}
        <button onClick={() => handleClickColor("red")}>빨강</button>
        <button onClick={() => handleClickColor("orange")}>주황</button>
        <button onClick={() => handleClickColor("yellow")}>노랑</button>
        <button onClick={() => handleClickColor("green")}>초록</button>
        <button onClick={() => handleClickColor("indigo")}>군청</button>
        <button onClick={() => handleClickColor("purple")}>보라</button>
      </div>
    </div>
  );
}

export default ColorSelector;

회원가입 양식 만들기

Form

  • html에서 Form 태그는 기본적으로 폼이 제출되면 페이지가 새로고침돼. (post 방식으로 보내기 때문에)

  • 하지만 우리는 그런방식으로 하지 않아서 이를 막아야해.

전체코드

import React, { useState } from "react";

function SignUpForm() {
  const [id, setId] = useState("");
  const [password, setPassword] = useState("");
  const [password2, setPassword2] = useState("");
  const [nickname, setNickname] = useState("");
  const [gender, setGender] = useState("");
  console.log(gender);
  const handleClickSignUp = () => {
    if (password !== password2) return alert("비밀번호 일치 X");
    const data = {
      id,
      password,
      nickname,
      gender,
    };
    console.log(data);
  };

  return (
    <div>
      <h2>회원가입 양식</h2>
      <form
        style={{
          display: "flex",
          flexDirection: "column",
          maxWidth: 200,
          margin: "0 auto",
          rowGap: 12,
        }}
        // 제출되면 기본동작을 막겠다(새로고침되는)
        onSubmit={(e) => e.preventDefault()}
      >
        <input
          type="text"
          placeholder="ID 입력해주세요"
          value={id}
          onChange={(e) => setId(e.target.value)}
        />
        <input
          type="password"
          placeholder="PW 입력해"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <input
          type="password"
          placeholder="PW 한번더 입력해"
          value={password2}
          onChange={(e) => setPassword2(e.target.value)}
        />
        <input
          type="text"
          placeholder="닉네임 입력해"
          value={nickname}
          onChange={(e) => setNickname(e.target.value)}
        />
        <div style={{ display: "flex" }}>
          <div>
            <input
              id="gender-female"
              type="radio"
              name="gender"
              value="female"
              checked={gender === "여자"}
              onChange={(e) => e.target.checked === true && setGender("여자")}
            />
            <label htmlFor="gender-female">여자</label>
          </div>

          <div>
            <input
              id="gender-male"
              type="radio"
              name="gender"
              value="male"
              checked={gender === "남자"}
              onChange={(e) => e.target.checked === true && setGender("남자")}
            />
            <label htmlFor="gender-male">남자</label>
          </div>
        </div>
        <button onClick={handleClickSignUp}> 가입하기</button>
      </form>
    </div>
  );
}

export default SignUpForm;

https://instructor-young.notion.site/f5de06b7bc824f03a3bc94c386f6c393

0개의 댓글