[코딩앙마] 리액트

유영준·2022년 11월 27일
0
post-thumbnail

자바스크립트의 기본 개념동작 원리를 정확히 이해하는 것이 중요!


개인적인 공부를 하면서 중요한 내용을 정리한 형식이기 때문에 오류가 있을 수 있습니다.
피드백 주시면 정말 감사하겠습니다.


npx create-react-app 프로젝트 이름

node_modules 폴더

  • 이 프로젝트를 실행할 때 필요한 dependency 모듈들이 모여 있음
  • package.json 파일의 'dependencies'에 기록되어 있음
  • package.json 파일 중 'scripts'
  • start: 개발 모드로 프로그램을 실행
  • build: 실제 배포 모드로 만들어 줌
  • test
  • eject: 내부 설정 파일을 꺼내는 역할, 웹페이지나 바벨 설정을 변경하고 싶을 떄 사용

컴포넌트, JSX

function App() {
  const name = "Tom";
  const naver = {
    name: "네이버",
    url: "https://naver.com",
  };
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>Coding angma</p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React~~~~!!
        </a>
      </header>
      <h1
        style={{
          color: "#f0f",
          backgroundColor: "green",
        }}
      >
        Hello, {name}.<p>{2 + 3}</p>
      </h1>
      <a href={naver.url}>{naver.name}</a>
    </div>
  );
}

CSS 작성법(module css)

  1. inline style 사용
<h1
	style={{
	color: "#f00",
    borderRight: "12px solid #000",
	marginBottom: "50px",
	opacity: 1,
	}}
>
	Hello
</h1>
  1. index.css, app.css 파일 사용
  • 이때 단점은 css 파일들이 각 컴포넌트에 종속되는 것이 아니라 html의 header 부분에 들어가서 모든 페이지에 영향을 미치게 됨
  1. css module 활용
  • 보통 '컴포넌트이름.module.css'로 파일 생성
  • 동일한 클래스 이름을 사용하더라도 각 컴포넌트 별로 다른 클래스 이름이 생성됨
  • 글로벌 단위가 아닌 컴포넌트 단위로 관리할 수 있어서 편리함
// jsx파일에는
import styles from "./Hello.module.css";

function Hello() {
  return (
    <div>
      <div className={styles.box}>Hello</div>
    </div>
  );
}

// module.css파일에는
.box {
  width: 200px;
  height: 50px;
  background-color: blue;
}

이벤트 처리(Handling Events)

export default function Hello() {
  function showName() {
    console.log("Mike");
  }
  function showAge(age) {
    console.log(age);
  }
  function showText(txt) {
    console.log(txt);
  }

  return (
    <div>
      <h1
        style={{
          color: "#f00",
          borderRight: "12px solid #000",
          marginBottom: "50px",
          opacity: 1,
      <h1>Hello</h1>
      <button onClick={showName}>Show name</button>
      <button
        onClick={() => {
          showAge(10);
        }}
      >
        Hello
      </h1>
      <div className={styles.box}>Hello</div>
        Show age
      </button>
      <input
        type="text"
        onChange={e => {
          const txt = e.target.value;
          showText(txt);
        }}
      />
    </div>
  );
}

State, useState

  • state: 컴포넌트가 가지고 있는 속성값
export default function Hello() {
  // let name = "Mike";
  const [name, setName] = useState("Mike");

  return (
    <div>
      <h2 id="name">{name}</h2>
      <button
        onClick={() => {
          setName(name === "Mike" ? "Jane" : "Mike");
        }}
      >
        Change
      </button>
    </div>
  );
}

Props

  • props로 전달받은 값을 props.age = 100 과 같이 직접적으로 변경 불가능 -> 변경 원한다면 useState 사용해야 함
// App.js
function App() {
  return (
    <div className="App">
      <h3>props : properties</h3>
      <Hello age={10} />
      <Hello age={20} />
      <Hello age={30} />
    </div>
  );
}

// Hello.js
import { useState } from "react";
import UserName from "./UserName";

export default function Hello({ age }) {
  const [name, setName] = useState("Mike");
  const msg = age > 19 ? "성인 입니다." : "미성년자 입니다.";

  return (
    <div>
      <h2 id="name">
        {name}({age}) : {msg}
      </h2>
      <UserName name={name} />
      <button
        onClick={() => {
          setName(name === "Mike" ? "Jane" : "Mike");
        }}
      >
        Change
      </button>
    </div>
  );
}

// userName.js
export default function UserName({ name }) {
  return <p>Hello, {name}</p>;
}

npm install react-router-dom

json-server, REST API
json-server: 빠르고 쉽게 rest api를 구축해 줌

npm install -g json-server

json-server --watch 더미데이터 있는 곳 --port 지금 사용하고 있지 않은 포트
json-server --watch ./src/db/data.js --port 3001

REST API

  • uri 주소와 method로 CRUD(Create: POST, Read: GET, Update: PUT, Delete: DELETE) 요청을 하는 것
useEffect, fetch()로 API 호출

useEffect

  • 상태 값이 변경되어 다시 랜더링 됐을 때 호출 됨
  • 어떤 상태 값이 바뀌었을 때 동작하는 함수를 만들 수 있음
  • 첫 번째 매개변수로 함수를 받음
  • 두 번째 매개변수로는 의존성 배열
    - 배열 안에 어떤 것이 변경되었을 때 호출될 지 작성
    - 랜더링 된 후 최초 1번만 호출하고 싶으면 빈 배열 사용
// DayList.js
useEffect(() => {
  fetch("http://localhost:3001/days")
    .then(res => {
      return res.json();
    })
    .then(data => {
      setDays(data);
    });
}, []);
  
// Day.js
useEffect(() => {
    fetch(`http://localhost:3001/words?day=${day}`)
      .then(res => {
        return res.json();
      })
      .then(data => {
        setWords(data);
      });
  }, [day]);

Custom Hooks

// useFetch.js
import { useEffect, useState } from "react";

export default function useFetch(url) {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch(url)
      .then(res => {
        return res.json();
      })
      .then(data => {
        setData(data);
      });
  }, [url]);

  return data;
}

// Day.js
const words = useFetch(`http://localhost:3001/words?day=${day}`);

// DayList.js
const days = useFetch("http://localhost:3001/days");

PUT(수정), DELETE(삭제)

// Word.js
function toggleDone() {
  // isDone 수정
  fetch(`http://localhost:3001/words/${word.id}`, {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      ...word,
      isDone: !isDone,
    }),
  }).then(res => {
    if (res.ok) {
      setIsDone(!isDone);
    }
  });
}

function del() {
  if (window.confirm("삭제 하시겠습니까?")) {
    fetch(`http://localhost:3001/words/${word.id}`, {
      method: "DELETE",
    }).then(res => {
      if (res.ok) {
        setWord({ id: 0 });
      }
    });
  }
}

// 단어의 id가 0이면 보이지 않게
if (word.id === 0) {
  return null;
}

POST(생성), useHistory()

  • Chrome 개발자 도구에서 Network를 'Online'에서 'Slow 3G'로 바꿔서 느린 환경을 가정하여 테스트 해볼 수 있음
// Day.js
{words.length === 0 && <span>Loading...</span>}

// CreateWord.js
if (!isLoading) {
  setIsLoading(true);
  fetch(`http://localhost:3001/words/`, {
    method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
    body: JSON.stringify({
      day: dayRef.current.value,
      eng: engRef.current.value,
      kor: korRef.current.value,
      isDone: false,
    }),
  }).then(res => {
    if (res.ok) {
      alert("생성이 완료 되었습니다");
      history.push(`/day/${dayRef.current.value}`);
      setIsLoading(false);
    }
  });
    
<button
      style={{
        opacity: isLoading ? 0.3 : 1,
      }}
>
  {isLoading ? "Saving..." : "저장"}
</button>

타입스크립트 적용

npm install typescript @types/node @types/react @types/react-dom @types/jest @types/react-router-dom
.js 파일은 .ts로, .jsx 파일은 .tsx 파일로 변경
// Word.tsx
interface IProps {
  word: IWord;
}

export interface IWord {
  day: string;
  eng: string;
  kor: string;
  isDone: boolean;
  id: number;
}

export default function Word({ word: w }: IProps) {}
profile
프론트엔드 개발자 준비 중

0개의 댓글