«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
관리 메뉴

코더

react 기본 + react 영단어 만들기 본문

카테고리 없음

react 기본 + react 영단어 만들기

자바스티안 2024. 5. 23. 15:33

--------------------------------react 기본----------------------------------------------

 

react 설치

npx create-react-app voca(npx => npm에 올라가있는 패키지를 바로 실행시켜준다)

 

npm start : 프로젝트 시작(띄운다)

 

(터미널에서)ctrl + c => 프로젝트를 내린다.

 

document.getElementById('root'); => index.html의 <div id = "root"></div>에 <APP />을 렌더링시켜준다.

 

jsx => javascript내부에 html처럼 작성하는 것

 

eject => 내부 설정파일을 꺼내는 역할을 한다.(웹페이지나,바벨설정 바꿀때 사용가능)

 

HMR => 개발 중에 모듈의 변경 사항을 즉시 적용

 

{} => 중괄호로 숫자나 문자열을 가져 올 수 있다.(boolean or 객체는 표현하지 못한다.)

 

  • / : 루트
  • ./ : 현재 위치
  • ../ : 현재 위치의 상단 폴더

./ => 현재 디렉토리를 나타내는 상대 경로이다.(바로 가져 올 수 있다 만약 아닐 시 상위폴더 가져와야함)

 

구조분해 할당 예시 : 

let {name, age} = user;

let name = user.name;

let age = user.age;

 

 

1.컴포넌트

 

app컴퍼넌트는 함수로 만들어져있고 이 app컴포넌트는 export default => index.js에서 import App from "./App";되어 사용된다

(내보낸 항목은 기본적으로 default로 가져오며, 해당 항목을 가져올 때 이름을 지정하지 않고 가져와서 사용할 수 있다.)

위와 같은 예시는 다음예시에서도 적용이된다

위의 app.js에서는 hello와 welcome 컴포넌트를 임폴트 해주고  hello에서는 welcome과 world를 임포트 해준다.

Hello

                           welcome jun11         ==> 결과값

world kim

welcome jun11

 

JSX는 하나의 태그만 사용가능하기 때문에 <div>태그로 <Hello />태그를 감싸주었다.

<Hello />태그는 안에 들어가는 내용이 없을 때 셀프클로즈 역할 해준다.

 

2.css

 

react는 인라인 스타일(html요소에 직접 스타일 속성을 지정)로 작성할때 객체 형태로 작성해야하면 camelCase(첫번째는 소문자 두번째 단어는 대문자)로 작성해야 한다.

ex)

<div style={{ color: "red", fontSize: "20px" }}>Hello World</div>

 

<div style = "color : red; font-size: 20px">Hello Worlc</div>

import World from "./World";
// import sty from "./Hello.module.css";


export default function Hello() {
return (
<div>
<h1
style = {{
color:"red",
borderRight:"12px solid #000",
marginBottom: "50px",
opacity: 0.5,
}}
>
Hello
</h1>
</div>
);
}

 

module.css파일을 이용하는 방법

 

App.css에 바로 .box를 만들고 Hello.css에 바로 .box를 만들면 오버라이딩이 되어 header부분에 코드가 들어가기 때문에 원하는 결과값이 나오지 않는다. 즉, App.module.css와 Hello.module.css를 만들어 준 후

import sty from "./Hello.module.css";
import styles from "./App.module.css";

두 코드를 App.js,Hello.js에 넣은후 

<div className={styles.box}>App</div>
<div className={styles.box}>App</div>

 

이렇게 코드를 넣으면 각 컴포넌트에 .box가 할당되는것을 알 수 있다.

import World from "./World";
import styles from "./Hello.module.css";


export default function Hello() {
return (
<div>
<h1
style = {{
color:"red",
borderRight:"12px solid #000",
marginBottom: "50px",
opacity: 0.5,
}}
>
Hello
</h1>
<div className={styles.box}>Hello</div>
</div>
);
}

===>Hello.js의 코드

 

3.이벤트 처리

 

event처리 하는방법

-1. 미리함수를 만들어 놓고 전달

-2.내부에서 직접 함수를 작성

export default function Hello() {
   function showName() {
   console.log("Hyeon")
}
 

return (
<div>
<h1>Hello</h1>
<button onClick={showName}>Show name</button>
<button
onClick={() => {
showAge(30)
}}
>
Show age
</button>
</div>
);
}

 

4.state

useState를 사용해서 상태값을 관리해준다.

 

import { userState } from "react";를 맨 첫번째 줄에 적어준다.

 

useState는 배열을 반환한다.

 

const [변수명,setName] = useSTate('초기값');

((변수명은 state이고 setNam은는 state를 변경해주는 함수이다.))

 

import { useState } from "react";

export default function Hello() {
// let name = "Mike"; //스테이트가 아닌 단순한 변수이다
const [name, setName] = useState("Mike");


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

react에서 사용 할 코드

export default function Hello() {
let name = "Mike";
//스테이트가 아닌 단순한 변수이다

function changeName() {
name = name === "Mike" ? "Jane" :"Mike";
console.log(name)
document.getElementById('name').innerText = name;
}

return (
<div>
<h1>state</h1>
<h2 id = "name">{name}</h2>
<button onClick = {changeName}>change</button>
</div>
);
}

자바스크립트라면 사용 할 코드

 

Props

-React에서 컴포넌트에 전달되는 데이터를 의미하는 객체

이 코드에서 Hello(props) 는 Hello({age})로 대체할 수 있다.

또한 구조분해 할당인데 예를 들어 const props = { age:30, name:”Mike”}; 라는값을 const age = props.age; const name = props.name이로 변수 할당을 할 수 있는데 이것을  const {age, name } = props 라고 구조분해할당  있기 때문이다. (즉, ({age}) 는 (props)라고 볼 수 있다.) 그럼 이 props.age는Hello.js파일에서의 age 즉, 가져오는 age값이 아닌 이 파일에서 만들어진 age값이라고 볼 수 있다.====> 너무 헷갈리면 뒤에있는 변수를 추출해서 구조분해 할당을 만든다 생각하자.

 

이런 식으로 한 컴포넌트가 가지고 있는 state를  props가 넘길 수 있다.( name은 이 컴포넌트에서는 state이지만 저 입장에서는 props이다. )

 

-------------------------------------react 영단어 만들기------------------------------------

 

 react 영단어 만들기

 

1.map()함수

 

-map()함수는 배열을 받아서 또 다른 배열을 반환하는 함수이다.

 

dummy.days.map(day => ())는 매개변수가 하나이기 때문에 dummy.days.map((day) => ()) 와 같고  

map 함수는 반드시 괄호를 동반한다.

 

data.json 파일 만들어 준후 day.js,daylist.js,header.js 파일은 새로운 app.js에 import 시켜준다.

 

2.react-router-dom 라우터 구현

 

npm install react-router-dom을 실행 한다.

 

<import BrowswerRouter, Route, Routes } from "react-router-dom"; 을 통해 import해준다.

 

return문 다음에 바로 BrowserRouter 로 감싸준다.

 

switch 대신 element = {<DayList /> } 와 같이 element를 사용하여 정확한 결과를 보여주게 되었다.

 

<Route path ="/day/:day" 에서 : day는 day라고 키로들어오는데 이 키의 값을 얻기위해서는 

 

import { userParams } from "react-router-dom"을 사용한다.

 

ex) 실제 이 :day에 무슨 값이 들어왔는지 알기위해서

const a = useParams();

console.log(a);

라고 하면 값이 키와 값이 {day : "2"}와 값이 찍히는 모습을 볼 수 있다.

 

"/*"는 원하는 링크로 접속하지 못하였을때 사용하면 된다. 그 후 ElementPage에 <Link to="/">돌아가기</Link>를 추가해서 돌아가기 버튼을 클릭하면 다시 처음 페이지 링크로 가는 코드를 만들었다.

 

3. useState

useState는 React 함수형 컴포넌트에서 상태(state)를 추가하고 관리하는 데 사용된다.

 

count [상태값, 상태값을 변경] = 초기값; 으로 구성된다 count[상태값, 상태값을 변경] = useState(file);

 

아래는 useState로 증가 감소를 나타내는 예시이다.

ex)

import React, { useState } from 'react';

function Counter() {
  // useState를 사용하여 초기값 0인 count 상태를 생성합니다.
  const [count, setCount] = useState(0);

  // 버튼 클릭 시 count 값을 증가시키는 함수
  const increment = () => {
    setCount(count + 1);
  };

  // 버튼 클릭 시 count 값을 감소시키는 함수
  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>Counter</h1>
      <p>Count: {count}</p>
      <button onClick={increment}>증가</button>
      <button onClick={decrement}>감소</button>
    </div>
  );
}

export default Counter;

 

                                                              1 .       import { useState } from "react"

useState(false);를 초기값으로 설정을 해((뜻을 숨기는 상태이다.)) !isShow를 클릭 할 시  !isShow 즉 true값을 반환한다.

Day.js 파일에서 Word 컴포넌트를 사용할 때 전달하는 war props는 해당 파일에서는 변수로 간주된다.(word를 코드에서 구별하기 위해 war로 바꾸었음) 그러나 전체적인 관점에서 보면 Day.js 파일에서 전체적으로는 Word 컴포넌트에 전달되는 props 중 하나이다

즉, Day.js 파일에서 Word 컴포넌트에게 전달되는 props 중 하나인 war는 해당 파일에서는 변수처럼 다루지만, 전체적인 관점에서는 Word 컴포넌트에게 전달되는 props의 일부분이다.

 

json server설치

npm install -g json-server

json-server --watch ./src/db/data.json --port 3001

 

4.useEffect

어떤 상태값이 바뀌었을 때 동작하는 함수를 작성 할 수 있다.(함수가 호출된 타이밍은 렌더링결과가 실제 DOM에 반영된 직후이다.)

 

의존성 배열 

useEffect 훅에 입력하는 두번째 매개변수(변경 될 때만 이 함수가 실행된다.) => 딱한번만 실행하려면  [] 빈배열을 전달한다.

 

fetch

//fetch 함수는 네트워크를 통해 리소스를 가져온다 즉,url에서 데이터 가져오는 http 요청을 만든다
//fetch 함수는 Promise를 반환(비동기적 네트워크 요청이 완료되면 그 결과를 나타내는 객체를 반환한다는 의미)하며, then 메서드를 사용하여 비동기적으로 데이터를 처리힌디. 첫 번째 then 블록에서는 HTTP 응답을 가져와서 JSON 형식으로 변환합니다.
-순서
  • fetch 요청이 http://localhost:3001/words?day=${day}에 보내진다.
  • 서버가 응답을 보내고, 이 응답이 JSON 형식으로 변환된다.
  • 변환된 JSON 데이터가 data 변수에 할당됩니다.
  • data 변수를 setWords(data)를 통해 words 상태로 설정하여, 이 상태를 기반으로 컴포넌트가 다시 렌더링 된다.( 즉, 기존에 import dummy ~~ 해서 dummy.words.map을 할 필요없이 이미 words가 json파일의 days나 day에 따른 word를 반환하기 때문에 바로 words.map을 사용 할 수 있고 import dummy 같은 코드도 필요가 없어진것이다.

 

mport { useParams } from "react-router-dom";
import Word from "./Word";
import { useState, useEffect } from "react";

export default function Day() {
// const a = useParams;
// const day = a.day;
// const wordList = dummy.words.filter(word => word.day === Number(day));
const { day } = useParams();
const [ words, setWords ] = useState([]);

useEffect(() => {
fetch(`http://localhost:3001/words?day=${day}`)
.then(res => {
return res.json();

})
.then(data =>{
setWords(data);
});
}, [day]);


return(
<>
<h2>Day {day}</h2>
<table>
<tbody>
{ words.map(word1 => (
<Word war={word1} key={word1.id} /> //이 Word 컴포넌트에서 war={word1}는 prop의 이름으로 사용되기 때문에 따로 정의 할 필요가 없다.
))}
</tbody>
</table>
</>
)
}

day.js

import { useState, useEffect } from "react";
import { Link } from "react-router-dom";

export default function DayList() {
const [ days, setDays ] = useState([]);

useEffect(() => {
fetch("http://localhost:3001/days")
.then(res => { //
return res.json();

})
.then(data =>{
setDays(data);
});
}, []);

return (
<ul className="list_day">
{days.map(d => (
<li key={d.id}>
<Link to = {`/day/${d.day}`}>Day {d.day}</Link>
</li>

))}
</ul>
);
}

DayList.js

 

5.useFetch

 

useFetch(url)을 통해 useEffect를 통해 const words = useFetch(`http://localhost:3001/words?day=${day}`)

로 day.js파일을 받았고

위와 같이 DayList.js에서는 http://localhost:3001:days를 통해 useFetch(url)의 함수를 받고 fetch(url)에서 주소를 받은 후 받은 값은 data에 return으로 받아준 후 days로 return된 data 값을 받아준다.

 

6,Put,Delete

==> Put 사용

body : { 는 수정을 위한 정보를 실어서 보내준다.

...war은 war 객체의 기존 속성들을 포함한다.

 

export default function Word({ war : w }) { //이름이 겹치게 하지 않으려 props로 받은 war을 변수명 w로 바꾸어 주었다.
const [war, setWar] = useState(w);
 
function del() {
if( window.confirm("삭제 하였습니다.")) {
fetch(`http://localhost:3001/words/${war.id}`, {
method : "DELETE",
}).then(res => {
if (res.ok) {
setWar({ id: 0 });
}
});
}
}

if (war.id === 0){
return null;
}
<button onClick={del} className="btn_del">삭제</button>
 

==> DELETE를 method로 지정해준 후 id 값이 0일때 삭제를 return null을 통해 삭제해준다. 당연히 <button onClick={del}을 추가해준다.

 

7.useRef

- input창에 적힌값을 알기위해 useRef 훅을 사용한다. => DOM에 접근 할 수 있게해준다.

import { useRef } from "react";

 

 

DOM

  • 가상 DOM: React가 상태나 속성 변경 시 메모리 내에서 유지하는 DOM의 사본이다. 가상 DOM은 실제 DOM을 효율적으로 업데이트하기 위해 사용된다. console.log로 출력되는 값은 가상 DOM의 상태를 나타낸다.
  • 실제 DOM: 웹 브라우저가 렌더링하는 실제 HTML 요소들이다. 이는 사용자가 화면에서 보는 내용입니다. 실제 DOM 조작은 브라우저에서 직접 이루어지며, 가상 DOM을 통해 최소화한다

따라서, 가상 DOM은 console.log에 찍히는 값과 관련이 있으며, 실제 DOM은 화면에 표시되는 내용을 의미한다. React는 가상 DOM을 사용하여 변경 사항을 추적하고, 필요한 부분만 실제 DOM에 반영함으로써 성능을 최적화한다.

 

useNavigate

-주소를 입력하면 해당 페이지로 이동을 한다.

import {useNavigate} from "react-router-dom";

const navigate = useNavigate();

if (res.ok) {navigate(`/day/${dayRef.current.value}`)

}을 사용한다.

import { useNavigate } from "react-router-dom";
import { useRef } from "react";
import useFetch from "../hooks/useFetch";

export default function CreateWord() {
const days = useFetch("http://localhost:3001/days");
const navigate = useNavigate();

function onSubmit(e){
e.preventDefault(); //Form 태그로 감싸줘 있기 때문에 새로고침이 안되게 하려면 e.preventdefault();를 사용해야 한다.

console.log(engRef.current.value); //current속성을 이용하면 해당 요소에 접근 할 수 있고,value는 input에 입력된 값을 얻을 수 있다.
console.log(korRef.current.value);
console.log(dayRef.current.value);
 

fetch(`http://localhost:3001/words/`, { //fetch( 주소 , 객체 ) // 객체는 요청의 옵션들을 입력한다. words까지만 입력하고 POST를 날리면 새로운 단어가 생성.
method: "POST",
headers: {
"Content-Type" : "application/json", // 보내는 리소스의 타입을 의미한다.( 평범한 문자열, html등 쓸 수 있다.)
},
body: JSON.stringify({
day : dayRef.current.value,
eng : engRef.current.value,
kor : korRef.current.value,
isDone: false,
}),
}).then(res => {
if (res.ok) { //서버로부터 응답이 성공적인 경우
alert("생성 완료");
navigate(`/day/${dayRef.current.value}`)
}
});
}

const engRef = useRef(null);
const korRef = useRef(null);
const dayRef = useRef(null);


return (
//input_area 클래스명은 주로 입력 요소와 관련된 요소들을 그룹화하거나 스타일링 할 때 사용된다.
<form onSubmit={onSubmit}>
<div className="input_area">
<label>Eng</label>
<input type="text" placeholder="computer" ref={engRef}/>
</div>
<div className="input_area">
<label>Kor</label>
<input type = "text" placeholder="컴퓨터" ref={korRef}/>
</div>
<div className = "input_area">
<label>Day</label>
<select ref={dayRef}>
{days.map(day => (
<option key={day.id} value={day.day}>
{day.day}
</option>
))}
</select>
</div>
<button>저장</button>
</form>
);
}

CreateWord.js

import { useNavigate } from "react-router-dom";
import useFetch from "../hooks/useFetch";

export default function CreateDay() {
const days = useFetch("http://localhost:3001/days");
const navigate = useNavigate();
 
function addDay() {
fetch(`http://localhost:3001/days/`, {
method : "POST",
headers : {
"Content-Type" : "application/json",
},
body : JSON.stringify({
day: days.length + 1,
}),
}).then(res => {
if (res.ok) {
alert("생성 완료");
navigate(`/`);
}
});
}

return (
<div>
<h3>현재 일수 : {days.length}</h3>
<button onClick={addDay}>Day 추가</button>
</div>
);
}

CreateDay.js

 

 

 

-------------------------------------------오류 해결------------------------------------------

1.

기존의 react 버전에서는 switch를 사용하여 Route exact path 를 통해 경로를 특정해 주었는데 이제는 element가 직접 받게 되어서 

기존의 <import BrowswerRouter, Route, Switch } from "react-router-dom"; 에서  <import BrowswerRouter, Route, Routes } from "react-router-dom"; 로 바꿔주었다 기존에 문법을 배울때에도 경로를 특정해주려 exact를 쓰는게 불편했는데 훨씬 간소화가 되어 좀 더 사용하기 편해진거 같다

 

function App() {

return (

<div className="App">

<Header />

<BrowserRouter>

<Routes>

<Route path="/" element={<DayList />} />

<Route path="/day/:day" element={<Day />} />

</Routes>

</BrowserRouter>

</div>

 

 

);

}

 

export default App;

 

기존의 이 코드가 오류가 계속 나서 생각을 해보니 Header태그 또한 BrowserRouter에 영향을 받는다는 것을 깨닫고 아래와 같이 고쳐주었다

function App() {
return (
<BrowserRouter>
<div className="App">
<Header />
<Routes>
<Route path="/" element={<DayList />} />
<Route path="/day/:day" element={<Day />} />
<Route path="/*" element={<EmptyPage />} />
</Routes>
</div>
</BrowserRouter>

);
}

export default App;

 

 

돌아갔다

 

2. 역시나 EmptyPage를 사용하기 위해서 /*를 사용해야 하는것을 찾기까지 좀 시간이 많이 걸렸다.(이것 또한 switch가 사용되지 않기 때문이라 생각한다.)

 

3.json server 설치 과정중에 npm install -g json-server 에서 오류가 발생해 sudo  npm install -g json-server 로 해결해주었다.(올바른 해결방법인지는 x)

 

4. react로 4일동안 계속고민하던 문제가 생겼었는데 너무 간단하게 해결이 되었다. 처음에 json-server --watch ./src/db/data.json --port 3001을 json파일을 설치하면서 zsh파일에 생성해주었는데 작업중인 콘솔작업에서 일을 하지않고 새로운 환경에서 작업을 해주던게 오류가 겹쳐 아예 정보가 넘어가지 않았다.