자바스크립트의 기본 개념과 동작 원리를 정확히 이해하는 것이 중요!
개인적인 공부를 하면서 중요한 내용을 정리한 형식이기 때문에 오류가 있을 수 있습니다.
피드백 주시면 정말 감사하겠습니다.
npx create-react-app 프로젝트 이름
node_modules 폴더
컴포넌트, 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)
<h1
style={{
color: "#f00",
borderRight: "12px solid #000",
marginBottom: "50px",
opacity: 1,
}}
>
Hello
</h1>
// 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) {}