Single Page Application 을 좀 더 쉽게 만들고 싶어서.
새로고침 없이 부드럽게 동작하는 웹 페이지를 좀 더 쉽게 만들고 싶어서.
가장 오래되고 가장 유저가 많아서.
HTML 의 재사용이 굉장이 편리하다.
컴포넌트 단위로 관리하기 때문.
React Native 로 앱 개발도 쉽게 할 수 있다.
Create React App 을 이용
npx create-react-app 프로젝트명
node_modules : 라이브러리 코드 보관함
npm 을 이용해서 무언가 설치하면 저 폴더에 들어간다
public : html, img 파일을 보관함
src : 소스코드 보관함. App.js 이 메인
package.json : 라이브러리를 설치하면 버전이나 설치정보 등이 들어간다
react 에서는 자바스크립트 내에 html 을 작성하는데,
jsx 는 js파일에서 html 을 좀 더 쉽게 작성할 수 있게 도와준다.
import "./App.css";
export default App;
import 한 css파일을 export defalut 해주면 적용된다.
자바스크립트로 html 태그를 추가하려면
document.querySelector('추가할대상').insertAdjacentHTML...
// 혹은
document.querySelector('추가할대상').createElement(...)
이런식으로 추가를 해야한다.
그런데 이러한 방식은 직관성도 떨어질 뿐더러 개발 난이도도 너무 어려워지므로 JSX 는 이러한 문제를 해결하여
function App() {
return (
<div className="App">
<div className="nav">
</div>
</div>
);
}
이런식으로 기존 HTML 파일을 개발하듯 코딩을 할 수 있다.
그런데 HTML 에서 선택자로 쓰이는 class 문법은 자바스크립트의 class 문법과 다르다.
예약어로 설정되어 있기 때문에 JSX에서는 class 문법을 className 으로 대체하여 사용한다.
function App() {
let post = '블로그';
return (
<div className="App">
<div className="nav">
<h4>{post}</h4>
</div>
</div>
);
}
return 상단에 변수를 선언하고 중괄호를 이용하여 변수를 사용할 수 있다.
변수를 HTML 에 넣어 사용하는 작업을 데이터바인딩 이라고 한다.
function App() {
let post = '블로그';
return (
<div className="App">
<div className="nav">
<h4 style={{color:'red', fontSize:'30px'}}>{post}</h4>
</div>
</div>
);
}
h4 부분을 보자.
기존 HTML 을 작성하던 방식과는 조금 다른데,
style 속성을 오브젝트 처럼 기입해야 적용할 수 있다.
sytle = {} 안에 오브젝트로 집어넣는다.
작성할 HTML 코드는 반드시 return() 내부에 작성해야 한다.
또한 병렬로 태그를 작성할 수 없다.
예를들어,
function App() {
return (
<div className="App">
</div>
<div></div>
);
}
이런식으로 작성할 수 없다.
react 식 변수를 저장하는 방법.
import {useState} from 'react';
function App(){
let [데이터내용,스테이트변경시실행할함수] = useState('데이터')
}
useState 는 배열로 저장이 되어 let [a,b] 식으로 정의하면 (구조분해할당 작업이다)
a에는 state 에 저장된 데이터, b는 state 가 변경되었을 때 실행할 함수를 가리킨다.
state 를 쓰는 이유가 무엇일까 ?
가장 큰 차이점이라면 state 는 변동사항이 생기면 state 를 사용하는 html 로 자동 재렌더링 해준다는 점에 있다.
기존의 변수는 변경되었을 때,
‘이 변수가 변경되면 html 을 변경해주세요’ 라고 따로 작업을 명령해주어야 하는데,
state 로 선언된 변수는 자동으로 재렌더링하여 변경한다.
새로고침을 하지 않아도 HTML 이 자동으로 변경되므로
single page app 개발에 좀 더 용이하다.
반대로 생각해서, 굳이 변경할 일이 없는
웹 사이트의 로고나 네이게이션 바의 항목 같은 경우에는 굳이 state 로 저장할 필요가 없다.
요점은 ‘변경이나 상태의 변화를 주시해야 하는 요소’를 state 로 저장하면 좋다는 것이다.
state 는 두개의 항목으로 정의된다.
function App(){
let [a,b] = useState('데이터들')
}
a가 데이터라면 b는 데이터가 변경되었을 때 재렌더링 해줄 함수를 명시한다고 했다.
자바스크립트의 이벤트를 이용해
특정 조건을 만족시키면 state를 변경해주십시오
라고 코딩을 한다면 어떨까 ?
우선 이벤트를 만들어보자.
function App(){
function func(){
console.log(1)
}
return (
<button onClick={func}> 버튼을 누르면콘솔에 1 출력 </button>
)
}
onClick 키워드를 사용하여 클릭이벤트를 감지해줄 수 있다.
onClick 내부에는 함수의 이름이 들어간다. 함수의 이름.
함수() 같은 식으로 함수의 실행하는 실수에 주의.
<button onClick={()=>{}}> 내용 <button>
함수명을 쓰지 않고 직접 함수를 정의하거나 arrow function 을 사용할 수도 있다.
직접 기능 개발을 해보자.
[1,2,3,4,5] 라는 배열이 state 로 저장되어 있고 이 배열을 출력해주는 span 을 만들었다.
특정 버튼을 클릭하면 버튼에 1씩 더해서 재렌더링 해주는 기능을 구현해보자.
function App() {
let [num, numChange] = useState([1, 2, 3, 4, 5]);
return (
<div className="App">
<button
onClick={() => {
let copy = [...num];
let change = [];
copy.forEach((e) => {
e++;
change.push(e);
});
numChange(change);
}}
>
change number
</button>
<span>{num}</span>
</div>
);
}
리엑트를 처음 써봐서 잘 된 코딩인지는 잘 모르겠다..
지금은 state 사용법을 익히는 중이니 수정할 수 있다면 나중에 한번 수정해보자.
순서대로 살펴보자면
우선 첫번째.
state 를 span 태그에 꺼내주기 위해 {} 중괄호로 num을 불러주었다.
두번째,
button에 onClick 이벤트를 추가하여 버튼을 클릭하면 감지하여 함수를 실행해 줄 수 있도록
onClick 내부에 함수를 구현했다.
세번째,
state 로 선언된 배열을 copy 라는 변수에 재할당했다.
재할당 하는 과정에서 spread operator 를 사용했다.
배열에 spread operator 를 사용한 후 다시 묶어주면 똑같은 새로운 배열을 만들 수 있다.
왜 이렇게 해야할까 ?
우선 개발을 할 때, 원본 데이터 수정을 지양해야 한다는 점과 깊은복사 & 얕은복사의 개념이다.
reference data type인 배열이나 오브젝트를 변수로 선언할 때,
해당 데이터를 복사해오는 것이 아니라 데이터가 저장된 장소의 주소를 저장한다.
따라서 이 경우에 예를들어 이런식으로,
<button
onClick={() => {
let copy = num;
let change = [];
copy.forEach((e) => {
e++;
change.push(e);
});
numChange(change);
}}
>
change number
</button>
state 배열을 그대로 copy 변수로 복사하려고 하면
변경점을 체크하여 재렌더링하는 state 의 변경함수가 작동하지 않는다.
왜냐하면 저런식의 복사는 주소
만 복사하기 때문에
내부의 데이터 변경 여부와는 상관없이 두 변수가 가리키는 주소
는 똑같기 때문이다.
깊은 & 얕은 복사 개념은 반드시 제대로 이해하고 넘어가야 할 것 같다.
완성된 구현내용
위에서 공부했던 것 처럼, 병렬로는 HTML 덩어리를 작성할 수 없다.
return() 안에 두개의 div box 를 만들 수 없다는 이야기.
반드시 두개의 div box 를 넣어야만 한다면
function App(){
return(
<div>
<div>기능개발</div>
<div>기능개발</div>
</div>
)
}
하나의 div로 묶는다거나,
function App(){
return(
<>
<div>기능개발</div>
<div>기능개발</div>
</>
)
}
의미없는 괄호를 사용하여 묶을 수 있다.
이 방법을 fragment 문법이라고 한다. 직역하자면 파편 혹은 부서진 조각 이라는 의미.
그렇다면 HTML 이 아주 많아지면 어떻게 해야할까 ?
그것들을 다 div로 묶는 것 보다 조금 더 편리한 방법이 react 의 component 문법.
예를들어,
function App() {
return(
<div>
<Comp2/>
</div>
)
}
function Comp2(){
return (
<div>기능개발</div>
)
}
사실 상단의 App 도 하나의 component 이다.
이렇게 축약한 HTML 덩어리를 component 라고 부른다.
react 개발의 핵심은 이런식으로 component 단위로 개발하는데 있다.
App() 의 return 내부에서 정의한 component를
<Comp2></Com2>
혹은
<Comp2/>
이런식으로 호출하면 해당 component 를 호출한 자리에 넣어 렌더링한다.
보통 component 의 첫 스펠링은 대문자로 기입하는게 관습이다.
component 는 정말 편리한 문법이고 이 기능이 react 의 핵심이지만 남발해서는 안된다.
왜냐하면 component 가 많으면 많을수록 유지보수가 힘들어지고,
변수의 선언 및 관리도 복잡해지기 때문이다.
따라서 component 는
이러한 경우에 만드는게 바람직하다.
동적인 UI 를 만들어보자.
기존의 자바스크립트로 UI를 개발할 때는,
1.html / css 로 초기상태, 최종상태 디자인을 한다.
2.특정 이벤트를 만족하면
3.초기상태에서 최종상태로 변경시킨다.
그런데 react 의 UI 개발은 다음과 같은 단계를 따른다.
- html / css 로 디자인을 한다.
- UI의 현재 상태를 state 로 저장한다.
- state 의 상태에 따라서 UI가 어떤 식으로 바뀔 지 조건문 등으로 판별한다.
기존의 자바스크립트와 조금 다른데,
자바스크립트는 UI를 만들 때 HTML 을 직접 조작해야한다.
style.background = ‘black’
이런식으로 말이다.
그런데 react 는 스위치의 온 오프 처럼
스위치가 ‘ON’ 이면 불이 켜지고, 스위치가 ‘OFF’ 이면 불이 꺼지는 식으로 개발을 한다.
예를들어, 버튼을 누르면 모달창을 띄워주는 UI를 개발한다고 하면
let [modal, setModal] = useState(false);
초기상태를 false 로 설정하고
버튼을 눌렀을 때 true 로 상태를 변경하는 식으로 코딩을 하면 되겠다.
주의할 점.
JSX 내부의 자바스크립트 표현식에서는 if, for 같은 자바스크립트 문법을 사용할 수 없다.
그렇다면 조건이 필요한 내용을 작성해야할 때는 어떻게 해야할까 ?
두 가지 방법이 있는데
삼항연산자는,
(조건 ? 참일경우 : 거짓일경우)
식의 조건문이다.
그럼 이제 모달창을 만들어보자.
위에서 state 는 정의 했으므로,
App() 의 return() 내부에
function App(){
return(
...
{modal == true ? <Modal></Modal> : null}
)
이런식으로 modal 의 값이 true 일 때 Modal component 를 띄워주고,
false 일 때 null, 존재하지 않게 만들면 되겠다.
return 내부는 JSX 의 영역이므로 삼항연산자를 사용했다.
<div className="list" onClick={showModal}></div>
이벤트를 감지할 대상에 onClick 이벤트로 함수를 선언하고 (콜백함수로 만들어도 무관)
function showModal() {
if (modal === false) {
setModal(true);
} else {
setModal(false);
}
}
만약 클릭했을 때 modal 의 값이 false 라면 state 를 true 로 변경해주고
true 일 경우에 false 로 바꿔주는 스위치 기능을 구현했다.
정의된 함수는 return 외부에 있으므로 if문을 사용해 구현한 모습.
구현한 내용