React를 거의 몇 달만에 다시 만지면서 기초부터 다시 해보자는 생각에 기록하게 되었다.
순서
1. 태그의 대소문자
2. 사용자 정의 태그(컴포넌트)의 위치
3. prop(속성) - props(속성들)
3.1 속성 배열 사용
4. 초기화하지 않은 함수의 일반형과 람다형
5. prop으로 이벤트 전달
6. state
7. useState
8. useState2
9. Create
10. Update
11. delete
전체 코드
1. 태그의 대소문자
- 소문자는 HTML 태그
- 대문자는 사용자 정의 태그
일반형
function Header() {
return (
<header>
<a href='/'>web</a>
</header>
)
}
람다형
const Header = (props) => {
return (
<header>
<a href='/'>web</a>
</header>
)
}
============================================================================================
2. 사용자 정의 태그 위치
- App보다 나중에 선언되어도 사용 가능
- React 컴포넌트도 JavaScript 함수나 클래스 선언과 동일한 방식으로 동작하기 때문
--> 컴포넌트는 함수로 정의되기 때문에, 호이스팅의 영향을 받아 컴포넌트가 사용되기 전에 선언될 필요가 없음
============================================================================================
3. prop(속성) - props(속성들)
- html태그의 속성과 같은 역할
- 속성을 부여하여 사용자 정의 태그를 건드리지 않고 내용을 변경시킬 수 있음
- js로 사용할 때는 그냥 사용
- html로 사용할 때는 {} 사용
const Header = (props) => {
console.log("props: ", props, props.title)
return (
<header>
<a href='/'>{props.title}</a>
</header>
)
}
function App(){
<div>
<Header title="React"></Header>
</div>
}
============================================================================================
3.1 속성 배열 사용
function App() {
const topics = [
{id:1, title:'html', body:'html is...'},
{id:2, title:'css', body:'css is...'},
{id:3, title:'js', body:'js is...'},
]
return (
<div>
<Nav topics = {topics}></Nav>
</div>
);
}
const Nav = (props) => {
const arrays = []
for (let index = 0; index < props.topics.length; index++) {
let element = props.topics[index];
arrays.push(<li key={element.id}><a href={'/read/' + element.id}>{element.title}</a></li>)
}
return(
<nav>
<ol>
{arrays}
</ol>
</nav>
)
}
1. App()에서 배열 생성
2. prop으로 배열 전달
3. Nav에서 props.topics라는 이름의 배열을 전달 받음
4. 받은 배열을 새로운 배열에 초기화하기 위해 새로운 배열 생성(arrays)
5. for 문을 사용해서 차례로 element에 전달 받은 배열값 초기화
--> 차례로 arrays 배열에 주입(push 사용)
- 이때 생성하는 arrays 배열 안의 속성값으로 props.topics의 값을 사용할 때는 {} 사용
============================================================================================
4. 초기화하지 않은 함수의 일반형과 람다형
function(){
alert("Header")
}
() => {
alert("Header")
}
============================================================================================
5. prop으로 이벤트 전달
<Nav topics={topics}
onChangeMode={(id) => {alert(id)}}>
</Nav>
- onChangeMode라는 이름의 속성으로 이하의 이벤트를 사용자 정의 태그에 전달
function(id){
alert(id)
}
const Nav = (props) => {
const arrays = []
for (let index = 0; index < props.topics.length; index++) {
let element = props.topics[index];
arrays.push(
<li key={element.id}>
<a href={'/read/' + element.id}
id={element.id}
onClick={(event) => { event.preventDefault();
props.onChangeMode(event.target.id);
}
}>{element.title}
</a>
</li>
)
}
return (
<nav>
<ol>
{arrays}
</ol>
</nav>
)
}
1. onClick이라는 이벤트 속성 추가
2. 클릭 시 발생할 수 있는 하이퍼링크 이벤트 차단( event.preventDefault(); )
3. 클릭 시 onChangeMode 속성을 App에서 가져와서 발동
4. function에서 사용하기 위한 변수를 현재 발동한 태그의 id로 지정(event.target은 이벤트를 유발한 태그 지정)
5. id값을 가져오기 위해 a태그에 id 속성 부여
============================================================================================
6. state
- prop은 컴포넌트 외부 사용자를 위한 데이터
- state는 컴포넌트 내부 사용자를 위한 데이터
function App() {
const mode = "READ"
let content = null;
if(mode === "WELCOME"){
content = <Article title="Welcome" body="Hello, web"></Article>
}
if(mode === "READ"){
content = <Article title="Read" body="This is for state"></Article>
}
return (
<div>
{content}
</div>
);
}
1. mode와 content를 초기화
2. mode의 값에 따라 content가 변화하는 코드 구현
3. {content}를 통해 mode의 값에 따라 출력이 변화하는 코드 구현
============================================================================================
7. useState
state를 변경할 때마다 자동으로 화면이 재랜더링되도록 해줌
import { useState } from 'react';
function App() {
const [mode, setMode] = useState("WELCOME"); // WELCOME이 state의 초기값
// mode[0] 현재 state의 값
// mode[1] 현재 state의 값을 변경할 때 사용하는 함수
let content = null;
if(mode === "WELCOME"){
content = <Article title="Welcome" body="Hello, web"></Article>
};
if(mode === "READ"){
content = <Article title="Read" body="This is for state"></Article>
};
return (
<div>
<Header title="Web" onChangeMode={() => {setMode("WELCOME")}}></Header>
<Nav topics={topics} onChangeMode={(id) => {setMode("READ")}} ></Nav>
{content}
</div>
);
}
1. useState import
2. 상수 [state명, setState명] = useState("초기값") 지정
3. 동적으로 값을 변경할 때, setMode을 활용
============================================================================================
8. useState2
function App() {
const topics = [
{ id: 1, title: 'html', body: 'html is...' },
{ id: 2, title: 'css', body: 'css is...' },
{ id: 3, title: 'js', body: 'js is...' },
];
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
let content = null;
if(mode === "READ"){
let title, body = null;
for (let index = 0; index < topics.length; index++) {
let element = topics[index];
if(element.id == id){
title = topics[index].title;
body = topics[index].body;
}
}
content = <Article title={title} body={body}></Article>
};
return (
<div>
<Nav topics={topics} onChangeMode={(id) => {setMode("READ"); setId(id)}} ></Nav>
{content}
</div>
);
}
1. const [id, setId] = useState(null);
2. mode가 "READ"일 때, title과 body를 null로 만들고 원하는 데이터를 다시 집어넣기
- for문을 사용해서 topics의 전체 번호를 조회하여 현재 누른 번호와 일치하는 json 데이터 찾기
- 현재 누른 번호와 일치하는 json 데이터의 title과 body를 넣기
## if(element.id == id)에서 ===이 아닌 이유
- 태그의 속성으로 값을 넘기면 int도 String으로 변경됨
- props.onChangeMode(event.target.id); 에서 값을 가져오는데 id={element.id}를 하면서 id가 int에서 String으로 변경되어 있음
- ===을 하면 int와 String을 비교하는 것이 되기 때문에 값을 찾아오지 못함
--> props.onChangeMode(Number(event.target.id));로 바꾸면 === 사용 가능
const Nav = (props) => {
const arrays = []
for (let index = 0; index < props.topics.length; index++) {
let element = props.topics[index];
arrays.push(
<li key={element.id}>
<a href={'/read/' + element.id}
id={element.id}
onClick={(event) => { event.preventDefault();
props.onChangeMode(event.target.id);
}
}>{element.title}
</a>
</li>
)
}
return (
<nav>
<ol>
{arrays}
</ol>
</nav>
)
}
============================================================================================
9. Create
function App() {
// 변수
let content = null;
// useState
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
const [topics, setTopics] = useState([ { id: 1, title: 'html', body: 'html is...' },
{ id: 2, title: 'css', body: 'css is...' },
{ id: 3, title: 'js', body: 'js is...' },
]);
const [nextId, setNextId] = useState(4);
// 조건에 따라 state값 변경
if(mode === "WELCOME"){
content = <Article title="Welcome" body="Hello, web"></Article>
};
if(mode === "READ"){
let title, body = null;
for (let index = 0; index < topics.length; index++) {
let element = topics[index];
if(element.id === id){
title = element.title;
body = element.body;
}
}
content = <Article title={title} body={body}></Article>
};
if(mode === "Create"){
content = <Create onCreate={(newTitle, newBody) => {
const newTopic = {id: nextId, title: newTitle, body: newBody}
const newTopics = [...topics];
newTopics.push(newTopic);
setTopics(newTopics);
setMode("READ");
setId(nextId);
setNextId(nextId + 1);
}
}
></Create>
}
// 출력
return (
<div>
<Header title="Web" onChangeMode={() => {setMode("WELCOME")}}></Header>
<Nav topics={topics} onChangeMode={(id) => {setMode("READ"); setId(id)}} ></Nav>
{content}
<a href='/create' onClick={(event) => {event.preventDefault(); setMode("Create");}}>Create</a>
</div>
);
}
function Create(props) {
return (
<article>
<h2>Create</h2>
<form onSubmit={(event) => {
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onCreate(title, body);
}}>
<p><input type='text' name='title' placeholder='title'></input></p>
<p><textarea name='body' placeholder='body'></textarea></p>
<p><input type='submit' value={"만들기"}></input></p>
</form>
</article>
)
}
1. App - 하이퍼링크 추가
<a href='/create' onClick={(event) => {event.preventDefault(); setMode("Create");}}>Create</a>
2. App - useState 추가
const [topics, setTopics] = useState([ { id: 1, title: 'html', body: 'html is...' },
{ id: 2, title: 'css', body: 'css is...' },
{ id: 3, title: 'js', body: 'js is...' },
]);
const [nextId, setNextId] = useState(4);
- topics: 이 배열에 새롭게 추가될 것
- nextId: topics 배열의 id 부여에 추가될 것
3. Create - form 작성
4. App - onCreate 함수 구현(newTopic 작성까지)
- Create에서 title과 body를 넘기면 해당 데이터를 바탕으로 const newTopic를 만듦
5. Create - onSubmit 함수 구현
- 기본 이벤트(페이지 새로고침)을 방지하고, event.target을 사용하여 title과 body 데이터를 불러옴
- App에서 구현된 onCreate 함수를 props.onCreate를 통해 title과 body를 App으로 전달
6. App - 받아온 데이터를 배열에 넣음
- const newTopics = [...topics]; 기존 배열을 복사
- newTopics.push(newTopic); 복사한 배열에 받아온 데이터를 추가
- setTopics(newTopics); 데이터를 추가한 새로운 배열을 통채로 set
- setMode("READ"); 모드 변경
- setId(nextId); id 값을 현재 아이디 값으로 변경
--> 새로 입력한 데이터가 출력됨
- setNextId(nextId + 1); 다음 데이터를 입력할 때는 초기값인 4가 아닌 5가 입력
============================================================================================
10. Update
function App() {
if(mode === "READ"){
let title, body = null;
for (let index = 0; index < topics.length; index++) {
let element = topics[index];
if(element.id === id){
title = element.title;
body = element.body;
}
}
content = <Article title={title} body={body}></Article>
contextControl = <li><a href={'/update/'+id} onClick={(event) => {event.preventDefault(); setMode("Update");}}>Update</a></li>
};
if(mode === "Update"){
let title, body = null;
for (let index = 0; index < topics.length; index++) {
let element = topics[index];
if(element.id === id){
title = element.title;
body = element.body;
}
}
content = <Update title={title} body={body} onUpdate={(updatedTitle, updatedBody) => {
const updatedTopic = {id: id, title: updatedTitle, body: updatedBody}
const updatedTopics = [...topics];
for (let index = 0; index < topics.length; index++) {
const element = topics[index];
if(element.id === id){
updatedTopics[index] = updatedTopic; // 기존 데이터를 갱신
break;
}
}
setTopics(updatedTopics);
setMode("READ");
}
}
></Update>
}
// 출력
return (
<div>
<ul>
<li><a href='/create' onClick={(event) => {event.preventDefault(); setMode("Create");}}>Create</a></li>
{contextControl}
</ul>
</div>
);
}
function Update(props){
const [title, setTitle] = useState(props.title); //바꿀 수 없는 데이터인 props를 state로 변경
const [body, setBody] = useState(props.body);
return (
<article>
<h2>Update</h2>
<form onSubmit={(event) => {
event.preventDefault();
// 저장된 데이터가 onUpdate 함수를 통해 App에 전달
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title, body);
}}>
{/* onChange를 통해 값을 입력할 때마다 setTitle을 통해 입력한 값을 state에 저장 */}
<p><input type='text' name='title' placeholder='title' value={title} onChange={(event) => {setTitle(event.target.value); }}></input></p>
<p><textarea name='body' placeholder='body' value={body} onChange={(event) => {setBody(event.target.value); }}></textarea></p>
<p><input type='submit' value={"업데이트"}></input></p>
</form>
</article>
)}
1. App - if(mode === "READ")일 때 업데이트가 출력되도록 코드 추가
contextControl = <li><a href={'/update/'+id} onClick={(event) => {event.preventDefault(); setMode("Update");}}>Update</a></li>
2. App - 출력하는 부분에 contextControl 추가
{contextControl}
3. App - if(mode === "Update")일 때 현재 출력되는 값을 찾기(READ와 동일)
let title, body = null;
for (let index = 0; index < topics.length; index++) {
let element = topics[index];
if(element.id === id){
title = element.title;
body = element.body;
}
}
==> 이를 통해 현재 업데이트할 데이터의 title과 body 정보를 가져올 수 있음
4. App - Update 함수로 title와 body 데이터 넘겨주기
content = <Update title={title} body={body}></Update>
5. Update - Update 함수 구현
A. props 데이터를 state 데이터로 바꾸기
- props 데이터는 외부에서 받는 것이기 떄문에 변경되지 않아 내부 사용자를 위한 데이터인 state로 변경
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
B. value에 받아온 title과 body를 속성으로 추가
value={title}
value={body}
C. onChange를 통해 값을 입력할 때마다 setTitle / setBody를 사용하여 state에 입력한 값을 저장
onChange={(event) => {setTitle(event.target.value);
onChange={(event) => {setBody(event.target.value);
=> props.onUpdate(event.target.title.value;, event.target.body.value;);
를 통해 다시 App으로 변경된 데이터가 전송
6. App - Update 함수에서 받은 데이터를 바탕으로 기존 데이터 재구성하기
A. const updatedTopic = {id: id, title: updatedTitle, body: updatedBody}
- 받아온 데이터로 updatedTopic 구성
- id는 Read 상태일 때 출력되기 때문에 그대로 사용 가능
B. const updatedTopics = [...topics];
- 기존 배열 복사
C. for (let index = 0; index < topics.length; index++) {
const element = topics[index];
if(element.id === id){
updatedTopics[index] = updatedTopic;
break;
}
}
- for문을 사용하여 배열 속 id 중 현재 id와 동일한 값을 찾고, 해당 데이터를 갱신
D. setTopics(updatedTopics);
- 데이터를 갱신한 새 배열을 set
E. setMode("READ");
- Read 상태로 변경
- id가 그대로 유지되기 때문에 id를 set할 필요는 없음
============================================================================================
11. Delete
contextControl = <>
<li><a href={'/update/'+id} onClick={(event) => {event.preventDefault(); setMode("Update");}}>Update</a></li>
<li><input type='button' value="삭제" onClick={()=>{
const newTopics = [];
for (let index = 0; index < topics.length; index++) {
const element = topics[index];
if(element.id !== id){
newTopics.push(element);
}
}
setTopics(newTopics);
setMode("WELCOME")
}}>
</input></li>
</>
1. <></> 빈 태그를 생성하고 update 옆에 delete 버튼 배치
2. onClick 이벤트 구현
A. const newTopics = [];
- 빈 배열 생성
B. for (let index = 0; index < topics.length; index++) {
const element = topics[index];
if(element.id !== id){
newTopics.push(element);
}
}
- for문을 사용하여 현재 아이디와 일치하지 않는 데이터만 배열에 추가
C. setTopics(newTopics);
- 새 배열을 set
D. 현재 id가 없기 때문에 기본값인 WELCOME으로 모드 변경
============================================================================================
'단순 코드 기록 > RE: React' 카테고리의 다른 글
redux toolkit 기초 (0) | 2024.05.23 |
---|---|
redux 기초 (0) | 2024.05.22 |
Context Api 기초 (0) | 2024.05.22 |
Styled Components 기초 (0) | 2024.05.22 |
Router 기초 (0) | 2024.05.21 |