https://yj-zero.tistory.com/86
React #8 [json, 리액트 라우터]
코딩앙마님의 강의를 보고 정리한 글입니다. https://www.youtube.com/watch?v=vI-XtN_Zdfg&list=PLZKTXPmaJk8J_fHAzPLH8CJ_HO_M33e7-&index=10 본격적인 페이지 만들기 이제 페이지를 만들기 위해 불필요한 파일..
yj-zero.tistory.com
이전 글의 내용에서 이어집니다.
코딩앙마님의 강의를 보고 정리한 내용입니다.
https://www.youtube.com/watch?v=B70lI2PvRnA&list=PLZKTXPmaJk8J_fHAzPLH8CJ_HO_M33e7-&index=13
이제 단어 목록에서 뜻 보기, 숨기기, 삭제, 체크박스를 만들어보자.
뜻보기, 숨기기, 삭제 버튼 만들기
<tr key={word.id}>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{word.kor}</td>
<td>
<button>뜻 보기</button>
<button class="btn_del">삭제</button>
</td>
</tr>
Day 컴포넌트에서 체크박스와 뜻 보기 버튼, 삭제 버튼을 만들어줬다.
이제 버튼을 구현하기 위한 단어 컴포넌트를 만들어주자. 따로 컴포넌트를 만드는 이유는 저 버튼들이 현재 페이지의 데이터 전체에 관련된 것이 아니라 단어 하나하나에 관련된 것이기 때문에 따로 관리해주는 것이 좋다.
export default function Word({word}){
return(
<tr key={word.id}>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{word.kor}</td>
<td>
<button>뜻 보기</button>
<button class="btn_del">삭제</button>
</td>
</tr>
)
}
Word 컴포넌트를 만들어서 단어 하나에 해당하는 부분을 Day 컴포넌트에서 가져와준다. 그리고 word에 대한 정보는 props로 받아온다.
<tbody>
{wordList.map(word => (
<Word word={word} key={word.id}/>
))}
</tbody>
이제 Day 컴포넌트에서 단어가 표시될 부분에 Word 컴포넌트를 사용한다. 그리고 props로 word를 전달하고 key 값을 설정해준다.
import { useState } from "react"
export default function Word({word}){
const [isShow, setIsShow] = useState(false);
function toggleShow(){
setIsShow(!isShow);
console.log(isShow);
}
return(
<tr>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{isShow && word.kor}</td>
<td>
<button onClick={toggleShow}>
뜻 {isShow ? "숨기기" : "보기"}
</button>
<button class="btn_del">삭제</button>
</td>
</tr>
)
}
뜻을 보이게 할지 말지를 정하기 위한 state 값을 설정하고 기본값을 false로 준다. 왜냐하면 뜻이 안 보이는 게 기본값이어야 하기 때문!
그다음 word.kor가 isShow가 true 일 때만 보이도록 한다.
버튼을 누를 때 toggleShow 함수가 작동해서 isShow의 값을 true면 false로 false면 true 바꾸게 한다.
바뀐 값에 따라 뜻이 보이면 버튼의 이름이 뜻 숨기기로, 뜻이 안 보이면 뜻 보기로 바뀌도록 한다.
체크박스 버튼 만들기
이제 체크박스를 체크하면 다 외웠다는 뜻으로 회색으로 표시되도록 만들어보자.
다 외웠는지 안 외웠는지 구분하기 위해 json 데이터에서 isDone 값을 이용할 것이다.
export default function Word({word}){
const [isShow, setIsShow] = useState(false);
const [isDone, setIsDone] = useState(word.isDone);
function toggleShow(){
setIsShow(!isShow);
console.log(isShow);
}
function toggleDone(){
setIsDone(!isDone);
}
return(
<tr className={isDone ? 'off' : ''}>
<td>
<input type="checkbox" checked={isDone} onChange={toggleDone}
/>
</td>
...
state를 만들어서 word의 isDone을 저장한다. 그다음 뜻 보기 버튼과 마찬가지로 toggleDone 함수를 만들어서 isDone의 값이 바뀌도록 한다.
input을 살펴보면 checked에 isDone을 설정해서 만약 isDone true인 경우 회색으로 표시되도록 하고, onChange를 이용해서 isDone의 값을 바꾼다.
마지막으로 tr의 클래스로 만약 isDone이 true 면 off를 아니면 공백으로 둔다.
하지만 여기서 새로고침을 하면 체크해뒀던 것이 날아가게 된다. 왜냐하면 더미 데이터는 고정적으로 변화하지 않았기 때문이다.
이제 사용자의 입장에서 삭제하고 입력하고 수정하는 방법을 알아보자.
그러기 위해서는 DB를 구축하는 API를 만들어야 한다. json-server를 이용해서 REST API를 만들어보자.
json-server 설치
이렇게 API를 구축하는 것은 귀찮은 일인데 이럴 때 유용한 것이 json-server이다. 공부하거나 작은 프로젝트를 진행할 때 json-server를 사용하면 좋다.
터미널에서 +를 눌러서 새로운 터미널을 열고
npm install -g json-server
를 입력해서 설치해준다.
설치가 완료되면
json-server --watch ./src/db/data.json --port 3001
를 해준다.
여기서!! window10의 경우 보안 오류가 발생할 수도 있다.
그럴 경우!
https://unit-15.tistory.com/83
[React] json-server --watch 실행 시 에러 해결
[React] json-server --watch 실행 시 에러 해결 npm install -g json-server 로 json-server를 설치한 후 --watch를 하였는데 아래와 같은 에러가 발생하였다. json-server : 이 시스템에서 스크립트를 실..
unit-15.tistory.com
이 글을 따라 하면 해결할 수 있다.
RESt API란?
: url과 메소드를 이용해서 CRUD를 하는 것.
Create | POST |
Read | GET |
Update | PUT |
Delete | DELETE |
여기서 오른쪽의 메소드를 사용한다.
이제 이 메소드를 이용해서 하는 작업은 data.json에 기록이 되기 때문에 페이지를 새로고침 하거나 창을 껐다가 켜도 내용이 유지가 된다.
이제 API로 데이터를 호출할 것이기 때문에 DayList 컴포넌트에서 dummy를 지운다.
import { useEffect } from "react";
import { Link } from "react-router-dom";
export default function DayList(){
const [days, setDays] = useState([]);
useEffect()
return <ul className="list_day">
{days.map(day => (
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>
))}
<li></li>
</ul>;
}
dummy를 지우고 days state를 만들어준다. 기본값은 빈 배열로 api로 받아온 데이터를 넣어줄 것이다.
그리고 dummy.days 였던 부분도 days로 바꿔준다!
이제 useEffect를 사용해볼 건데
useEffect도 useState와 마찬가지도 어떤 선택 값이 바뀌었을 때 동작하는 함수를 만들 수 있다.
useEffect는 첫 번째 매개변수로 함수를 받는다.
useEffect의 함수가 호출되는 타이밍은 랜더링 된 결과가 DOM에 반영된 직후이다. 그리고 컴포넌트가 사라지기 직전에도 마지막으로 호출된다.
useEffect의 예시로 count 버튼을 만들어서 버튼을 누를 때마다 1씩 증가시켜보자.
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
export default function DayList(){
const [days, setDays] = useState([]);
const [count, setCount] = useState(0);
function onClick(){
setCount(count+1);
}
useEffect(() =>{
console.log("Count Change");
}
)
return <>
<ul className="list_day">
{days.map(day => (
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>
))}
</ul>
<button onclick={onClick}>{count}</button>
</>
}
코드를 작성하고 실행하면 버튼을 누를 때마다 콘솔에 Count change가 찍힌다.
이렇게 useEffect 상태 값이 변경돼서 다시 랜더링 된 후 호출되는 것을 볼 수 있다.
그래서 랜더링을 끝내고 어떤 작업을 하고 싶다면(API 호출 등) useEffect를 사용하면 된다.
그런데 이렇게 해주면 값이 변경될 때마다 불필요하게 호출될 수 있다.
이럴 땐 useEffect의 두 번째 매개변수로 배열을 전달하고 내용으로는 원하는 state를 넣어준다. 그러면 그 state 값이 변경됐을 때만 useEffect가 호출된다. 이런 것을 의존성 배열이라고 한다.
우리의 목적은 랜더링이 되고 API를 최초 한 번만 호출하는 것이다. 그러려면 의존성 배열을 빈 배열로 두면 된다. 그러면 최초 한 번만 호출된다!
이제 API를 통해 데이터를 받아보자.
//DayList
useEffect(() =>{
fetch('http://localhost:3001/days')
.then(res => {
return res.json()
})
.then(data => {
setDays(data);
})
}, []);
비동기적으로 처리하기 위해 fetch를 사용한다. json-server를 통해 만들어진 주소를 입력해주면 promise가 반환된다.
그러면 첫 번째 then을 통해서 promise를 json 형태로 만들어주고 두 번째 then을 통해서 days에 data 내용을 넣어준다.
이제 더미 데이터를 사용했던 부분들을 다 수정해보자.
//Day.js
const [words, setWords] = useState([]);
useEffect(() =>{
fetch(`http://localhost:3001/words?day=${day}`)
.then(res => {
return res.json()
})
.then(data => {
setWords(data);
});
}, [day]);
Day 컴포넌트에서도 DayList 컴포넌트와 거의 유사하게 받아오면 된다. 받아오는 주소는 words인데 day값에 따라 단어가 분류될 수 있도록 수식을 넣어준다.
의존성 배열에는 day 값을 넣어주어 day값이 변경될 때 다시 호출될 수 있도록 한다.
그런데 DayList에서 useEffect 부분과 Day 부분에서 useEffect 부분은 주소나 일부를 제외하고 매우 흡사하다. 이런 경우 Custom Hooks을 사용할 수 있다.
Custom Hooks
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;
}
달라질 수 있는 부분은 url로 받아오고 state의 이름은 다양한 곳에서 사용할 수 있도록 data로 변경하였다. 그리고 최종적으로 필요한 값인 data를 리턴한다.
이제 이렇게 만든 useFetch 훅을 사용해보자.
//Day.js
const words = useFetch(`http://localhost:3001/words?day=${day}`);
//DayList.js
const days = useFetch('http://localhost:3001/days');
이렇게 간단하게 한 줄로 표현할 수 있다.
반복적으로 사용되는 기능을 훅으로 만들면 코드 상으로도 더 간결해질 수 있고 수정하고 싶을 땐 만들어둔 훅만 수정하면 돼서 편하다!
'개발 공부 > React' 카테고리의 다른 글
React - Fragment 사용하기 (0) | 2022.09.19 |
---|---|
React #10 [PUT, DELETE] (0) | 2022.09.12 |
React #8 [json, 리액트 라우터] (0) | 2022.08.26 |
React #7 [컴포넌트, CSS, 이벤트, state, props] (0) | 2022.08.23 |
React #6 [update, delete] (0) | 2022.08.09 |
https://yj-zero.tistory.com/86
React #8 [json, 리액트 라우터]
코딩앙마님의 강의를 보고 정리한 글입니다. https://www.youtube.com/watch?v=vI-XtN_Zdfg&list=PLZKTXPmaJk8J_fHAzPLH8CJ_HO_M33e7-&index=10 본격적인 페이지 만들기 이제 페이지를 만들기 위해 불필요한 파일..
yj-zero.tistory.com
이전 글의 내용에서 이어집니다.
코딩앙마님의 강의를 보고 정리한 내용입니다.
https://www.youtube.com/watch?v=B70lI2PvRnA&list=PLZKTXPmaJk8J_fHAzPLH8CJ_HO_M33e7-&index=13
이제 단어 목록에서 뜻 보기, 숨기기, 삭제, 체크박스를 만들어보자.
뜻보기, 숨기기, 삭제 버튼 만들기
<tr key={word.id}>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{word.kor}</td>
<td>
<button>뜻 보기</button>
<button class="btn_del">삭제</button>
</td>
</tr>
Day 컴포넌트에서 체크박스와 뜻 보기 버튼, 삭제 버튼을 만들어줬다.
이제 버튼을 구현하기 위한 단어 컴포넌트를 만들어주자. 따로 컴포넌트를 만드는 이유는 저 버튼들이 현재 페이지의 데이터 전체에 관련된 것이 아니라 단어 하나하나에 관련된 것이기 때문에 따로 관리해주는 것이 좋다.
export default function Word({word}){
return(
<tr key={word.id}>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{word.kor}</td>
<td>
<button>뜻 보기</button>
<button class="btn_del">삭제</button>
</td>
</tr>
)
}
Word 컴포넌트를 만들어서 단어 하나에 해당하는 부분을 Day 컴포넌트에서 가져와준다. 그리고 word에 대한 정보는 props로 받아온다.
<tbody>
{wordList.map(word => (
<Word word={word} key={word.id}/>
))}
</tbody>
이제 Day 컴포넌트에서 단어가 표시될 부분에 Word 컴포넌트를 사용한다. 그리고 props로 word를 전달하고 key 값을 설정해준다.
import { useState } from "react"
export default function Word({word}){
const [isShow, setIsShow] = useState(false);
function toggleShow(){
setIsShow(!isShow);
console.log(isShow);
}
return(
<tr>
<td>
<input type="checkbox" />
</td>
<td>{word.eng}</td>
<td>{isShow && word.kor}</td>
<td>
<button onClick={toggleShow}>
뜻 {isShow ? "숨기기" : "보기"}
</button>
<button class="btn_del">삭제</button>
</td>
</tr>
)
}
뜻을 보이게 할지 말지를 정하기 위한 state 값을 설정하고 기본값을 false로 준다. 왜냐하면 뜻이 안 보이는 게 기본값이어야 하기 때문!
그다음 word.kor가 isShow가 true 일 때만 보이도록 한다.
버튼을 누를 때 toggleShow 함수가 작동해서 isShow의 값을 true면 false로 false면 true 바꾸게 한다.
바뀐 값에 따라 뜻이 보이면 버튼의 이름이 뜻 숨기기로, 뜻이 안 보이면 뜻 보기로 바뀌도록 한다.
체크박스 버튼 만들기
이제 체크박스를 체크하면 다 외웠다는 뜻으로 회색으로 표시되도록 만들어보자.
다 외웠는지 안 외웠는지 구분하기 위해 json 데이터에서 isDone 값을 이용할 것이다.
export default function Word({word}){
const [isShow, setIsShow] = useState(false);
const [isDone, setIsDone] = useState(word.isDone);
function toggleShow(){
setIsShow(!isShow);
console.log(isShow);
}
function toggleDone(){
setIsDone(!isDone);
}
return(
<tr className={isDone ? 'off' : ''}>
<td>
<input type="checkbox" checked={isDone} onChange={toggleDone}
/>
</td>
...
state를 만들어서 word의 isDone을 저장한다. 그다음 뜻 보기 버튼과 마찬가지로 toggleDone 함수를 만들어서 isDone의 값이 바뀌도록 한다.
input을 살펴보면 checked에 isDone을 설정해서 만약 isDone true인 경우 회색으로 표시되도록 하고, onChange를 이용해서 isDone의 값을 바꾼다.
마지막으로 tr의 클래스로 만약 isDone이 true 면 off를 아니면 공백으로 둔다.
하지만 여기서 새로고침을 하면 체크해뒀던 것이 날아가게 된다. 왜냐하면 더미 데이터는 고정적으로 변화하지 않았기 때문이다.
이제 사용자의 입장에서 삭제하고 입력하고 수정하는 방법을 알아보자.
그러기 위해서는 DB를 구축하는 API를 만들어야 한다. json-server를 이용해서 REST API를 만들어보자.
json-server 설치
이렇게 API를 구축하는 것은 귀찮은 일인데 이럴 때 유용한 것이 json-server이다. 공부하거나 작은 프로젝트를 진행할 때 json-server를 사용하면 좋다.
터미널에서 +를 눌러서 새로운 터미널을 열고
npm install -g json-server
를 입력해서 설치해준다.
설치가 완료되면
json-server --watch ./src/db/data.json --port 3001
를 해준다.
여기서!! window10의 경우 보안 오류가 발생할 수도 있다.
그럴 경우!
https://unit-15.tistory.com/83
[React] json-server --watch 실행 시 에러 해결
[React] json-server --watch 실행 시 에러 해결 npm install -g json-server 로 json-server를 설치한 후 --watch를 하였는데 아래와 같은 에러가 발생하였다. json-server : 이 시스템에서 스크립트를 실..
unit-15.tistory.com
이 글을 따라 하면 해결할 수 있다.
RESt API란?
: url과 메소드를 이용해서 CRUD를 하는 것.
Create | POST |
Read | GET |
Update | PUT |
Delete | DELETE |
여기서 오른쪽의 메소드를 사용한다.
이제 이 메소드를 이용해서 하는 작업은 data.json에 기록이 되기 때문에 페이지를 새로고침 하거나 창을 껐다가 켜도 내용이 유지가 된다.
이제 API로 데이터를 호출할 것이기 때문에 DayList 컴포넌트에서 dummy를 지운다.
import { useEffect } from "react";
import { Link } from "react-router-dom";
export default function DayList(){
const [days, setDays] = useState([]);
useEffect()
return <ul className="list_day">
{days.map(day => (
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>
))}
<li></li>
</ul>;
}
dummy를 지우고 days state를 만들어준다. 기본값은 빈 배열로 api로 받아온 데이터를 넣어줄 것이다.
그리고 dummy.days 였던 부분도 days로 바꿔준다!
이제 useEffect를 사용해볼 건데
useEffect도 useState와 마찬가지도 어떤 선택 값이 바뀌었을 때 동작하는 함수를 만들 수 있다.
useEffect는 첫 번째 매개변수로 함수를 받는다.
useEffect의 함수가 호출되는 타이밍은 랜더링 된 결과가 DOM에 반영된 직후이다. 그리고 컴포넌트가 사라지기 직전에도 마지막으로 호출된다.
useEffect의 예시로 count 버튼을 만들어서 버튼을 누를 때마다 1씩 증가시켜보자.
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
export default function DayList(){
const [days, setDays] = useState([]);
const [count, setCount] = useState(0);
function onClick(){
setCount(count+1);
}
useEffect(() =>{
console.log("Count Change");
}
)
return <>
<ul className="list_day">
{days.map(day => (
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>
))}
</ul>
<button onclick={onClick}>{count}</button>
</>
}
코드를 작성하고 실행하면 버튼을 누를 때마다 콘솔에 Count change가 찍힌다.
이렇게 useEffect 상태 값이 변경돼서 다시 랜더링 된 후 호출되는 것을 볼 수 있다.
그래서 랜더링을 끝내고 어떤 작업을 하고 싶다면(API 호출 등) useEffect를 사용하면 된다.
그런데 이렇게 해주면 값이 변경될 때마다 불필요하게 호출될 수 있다.
이럴 땐 useEffect의 두 번째 매개변수로 배열을 전달하고 내용으로는 원하는 state를 넣어준다. 그러면 그 state 값이 변경됐을 때만 useEffect가 호출된다. 이런 것을 의존성 배열이라고 한다.
우리의 목적은 랜더링이 되고 API를 최초 한 번만 호출하는 것이다. 그러려면 의존성 배열을 빈 배열로 두면 된다. 그러면 최초 한 번만 호출된다!
이제 API를 통해 데이터를 받아보자.
//DayList
useEffect(() =>{
fetch('http://localhost:3001/days')
.then(res => {
return res.json()
})
.then(data => {
setDays(data);
})
}, []);
비동기적으로 처리하기 위해 fetch를 사용한다. json-server를 통해 만들어진 주소를 입력해주면 promise가 반환된다.
그러면 첫 번째 then을 통해서 promise를 json 형태로 만들어주고 두 번째 then을 통해서 days에 data 내용을 넣어준다.
이제 더미 데이터를 사용했던 부분들을 다 수정해보자.
//Day.js
const [words, setWords] = useState([]);
useEffect(() =>{
fetch(`http://localhost:3001/words?day=${day}`)
.then(res => {
return res.json()
})
.then(data => {
setWords(data);
});
}, [day]);
Day 컴포넌트에서도 DayList 컴포넌트와 거의 유사하게 받아오면 된다. 받아오는 주소는 words인데 day값에 따라 단어가 분류될 수 있도록 수식을 넣어준다.
의존성 배열에는 day 값을 넣어주어 day값이 변경될 때 다시 호출될 수 있도록 한다.
그런데 DayList에서 useEffect 부분과 Day 부분에서 useEffect 부분은 주소나 일부를 제외하고 매우 흡사하다. 이런 경우 Custom Hooks을 사용할 수 있다.
Custom Hooks
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;
}
달라질 수 있는 부분은 url로 받아오고 state의 이름은 다양한 곳에서 사용할 수 있도록 data로 변경하였다. 그리고 최종적으로 필요한 값인 data를 리턴한다.
이제 이렇게 만든 useFetch 훅을 사용해보자.
//Day.js
const words = useFetch(`http://localhost:3001/words?day=${day}`);
//DayList.js
const days = useFetch('http://localhost:3001/days');
이렇게 간단하게 한 줄로 표현할 수 있다.
반복적으로 사용되는 기능을 훅으로 만들면 코드 상으로도 더 간결해질 수 있고 수정하고 싶을 땐 만들어둔 훅만 수정하면 돼서 편하다!
'개발 공부 > React' 카테고리의 다른 글
React - Fragment 사용하기 (0) | 2022.09.19 |
---|---|
React #10 [PUT, DELETE] (0) | 2022.09.12 |
React #8 [json, 리액트 라우터] (0) | 2022.08.26 |
React #7 [컴포넌트, CSS, 이벤트, state, props] (0) | 2022.08.23 |
React #6 [update, delete] (0) | 2022.08.09 |