[React] React 기본정리
왜 리액트가 필요한가
리액트 왜 배우시려고하는 것입니까
남들 다 하니까요?
그것도 맞는데 Web app이란걸 만들기 위해 React를 배워서 그 문법으로 웹사이트를 제작하는 겁니다.
웹앱은 Vibe, Flipkart, Instagram 이런 사이트들을 웹앱이라고 부릅니다.
다른페이지로 넘어가거나 포스팅을 발행하거나 그런 행동을 해도 새로고침이 되지 않고 스무스하게 동작합니다.
모바일 앱이랑 느낌이 비슷해서 앱이라고 부르는 것이죠.
요즘 대기업이든 중소기업이든 사이트를 새로 만들 때 굳이 필요없어도 자주 웹앱을 사용합니다.
그 이유는
UX가 뛰어나서 좋은 사용자경험을 제공하니까
HTML 관리가 편해지고
구매전환율도 높아지고
리액트 문법으로 iOS/Android 모바일 앱제작도 가능하고
서버개발자가 편해져서
그렇습니다.
이걸 어떻게 만드냐면.. 자바스크립트로 AJAX랑 HTML 조작을 떡칠해서 만들면 됩니다.
코드가 100줄 1000줄이 나오면서 고생좀 하겠죠?
그래서 React, Angular, Vue 라는 라이브러리를 쓰시면 훨씬 짧고 간결한 코드로 개발이 가능합니다.
그래서 가장 유명하고 사용자가 많은 React를 배우시면 취업이든 개인 프로젝트든 사업이든 많은 도움이 됩니다.
거의 요즘 웹개발자 엔드스펙이라고 보셔도 되겠습니다.
필요한 자바스크립트 사전지식
var let const function return for if else array object addEventListener
- 약간의 HTML CSS
React 설치와 개발환경 셋팅
- 구글에 Nodejs 검색해서 LTS라고 써있는 버전을 설치합시다.
13버전이하 아니면 17버전은 쓰면 안됩니다.
설치 경로는 C드라이브 어쩌구 되어있는거 바꾸지말고 그대로 쓰는게 좋습니다.
설치 중 chocolatey 어쩌구는 설치 안하셔도 됩니다.
- Visual Studio Code 에디터도 구글에 검색해서 설치합니다.
(기존 에디터 쓰셔도 되지만 터미널을 기존에 안다뤄본 분들은 필수)
Q. 맥북은 다른가요?
A. 다른거 없음 똑같습니다
리액트 프로젝트 생성은
- 작업용 폴더를 하나 만들어줍니다
찾기좋게 바탕화면에 만드는게 어떨까요.
- 폴더에 shift + 우클릭해서 여기서 powershell 열기를 누릅니다.
맥북은 손가락 두개 클릭해서 터미널열기 누르면 됩니다.
- 그럼 터미널이라는게 나오는데
npx create-react-app blog
이거 그대로 입력하고 엔터누르면 프로젝트 생성 끝입니다.
blog 대신 여러분의 리액트 프로젝트명을 기입해보십시오
안되면 하단을 참고해서 에러를 해결해봅시다.
- 에디터에서 프로젝트 오픈하려면
프로젝트 설치했으면 프로젝트이름의 폴더가 하나 생성되는데 (저는 blog)
그 폴더를 에디터로 오픈해서 코드짜면 됩니다.
Visual studio code 에디터 켠 다음에 File - Open Folder 누른다음에 아까 생성된 blog 폴더 선택하면 됩니다.
- App.js가 메인페이지임
src 폴더 안에 있는 App.js 이게 메인페이지니까 거기다가 코드짜면 됩니다.
- 내 사이트를 브라우저로 미리보기 띄우고 싶으면
에디터 상단메뉴중에 Terminal - New Terminal 누릅니다.
그럼 터미널이 뜨는데 거기다가 npm start 입력후 엔터치면 미리보기 뜹니다.
저처럼 blog 같은 프로젝트명이 터미널에 안뜨면 폴더오픈을 제대로 안한것입니다. 폴더 오픈부터 잘하십쇼
브라우저 자동으로 안뜨면 localhost:3000 이라고 크롬 브라우저 열고 직접 입력해주세요
터미널에 뭐 입력할 때 20% 확률로 에러가 뜹니다.
해결방법을 알아봅시다. 이러면 대부분 해결이고 이거 외엔 구글검색 ㄱㄱ
Q1. 저는 리액트 프로젝트 설치가 10분 이상 오래걸려요
스타벅스에서 하지 말고 집에서 합시다.
Q2. “npx command not found 어쩌구” 에러
터미널 다시 껐다 켜보세요
대부분 nodejs 제대로 설치 안해서 그렇습니다. 옛날 버전이라 그럴 수 있습니다.
맥북이면 brew 그런거 쓰지 말고 다운받읍시다.
윈도우는 C 드라이브에 얌전히 설치합시다.
리눅스는 알아서 nodejs 설치나 버전 업데이트 명령어 잘 입력하면 될듯요
Q3. 맥북인데 “permission이 없어요” 에러
프로젝트 생성시 저런 에러가 뜨면 터미널에
sudo npx create-react-app blog 입력해보면 됩니다.
비번입력하라고 하면 맥북 비번 입력하면 됩니다.
Q4. 윈도우인데 “허가되지 않은 스크립트 입니다 어쩌구~” 에러
윈도우 하단 검색메뉴에서 Powershell 검색 - 우클릭 - 관리자 권한으로 실행한 뒤
Set-ExecutionPolicy Unrestricted
라고 대소문자 하나라도 틀리지않고 입력하고 엔터칩니다.
그 다음에 뭐 선택하라고 하면 y 누르고 엔터치면 될듯요
그럼 이제 npx, npm으로 뭐 하는거 잘됩니다.
Q5. The engine “node” is incompatible with this module 에러
npx로 설치시 이런 에러가 있을 수 있습니다. nodejs 버전이 낮거나 너무 높다는 뜻이며
nodejs를 요구하는 버전으로 재설치하시면 됩니다.
Q6. 윈도우인데 아직도 터미널에서 뭐 하는거 안되면
이상한 보안프로그램 끄십시요 특히 Ahnlab security 어쩌구
작업폴더를 오픈한 다음 파일 - Powershell 열기 - 관리자권한으로 열기 누른 다음
거기서 npx 어쩌구 해서 프로젝트 생성해봅시다.
이외에도 에러 경우의 수가 매우 많기 때문에 정확한 에러메시지 직접 검색이 답입니다.
(참고)
버전에러 등으로 강의와 같은 리액트 버전에서 코딩하고 싶다면
하단 첨부파일을 압축푸신 뒤에 그 폴더를 에디터로 오픈합니다.
에디터 상단에서 Terminal - New Terminal 오픈하신 다음 npm install 을 입력하시면 필요한 라이브러리들이 설치됩니다.
이제 똑같이 코딩하시면 됩니다.
(문제가 생길경우 그럴 때 빼곤 굳이 저랑 똑같은 버전을 맞출 필요는 없습니다.)
리액트에서 레이아웃 만들 때 쓰는 JSX 문법 3개
이상한 사람들이 리액트 쓸데없이 어렵게 가르치는데
리액트라고 뭔가 어렵고 복잡하게 코드짜야하고 그런거 아닙니다.
그냥 기존처럼 html css 짜서 웹페이지 만들어나가면 됩니다.
그런데 html 대신 JSX라는걸 쓰는데 이거 사용법을 알아봅시다.
리액트프로젝트의 App.js로 들어갑시다
App.js가 여러분의 메인페이지입니다.
여기 이미 채워져있던 쓸데없는 html들은 싹 비우고 시작합시다.
div> 하나만 남기면 됩니다.
import 어쩌구;
function App(){
return (
<div className="App">
//다지움 ㅅㄱ
</div>
)
}
이제 깔끔한 백지상태에서 시작할 수 있습니다.
코드 수정했으면 파일 저장을 해야 미리보기 화면에서 잘 보입니다.
본격적으로 블로그 상단 nav를 제작해봅시다.
간단한 블로그를 만들어볼 것인데 상단메뉴가 있으면 좋을 것 같으니 만들어봅시다.
리액트 환경이라고 뭔가 다르고 심오하게 코드짠다고 오해하는 분들이 많은데
웹페이지 레이아웃은 그냥 옛 방식 그대로 똑같이 <div> 떡칠해서 짜면 됩니다.
(App.js)
function App(){
return (
<div className="App">
<div className="black-nav">
<h4>블로그임</h4>
</div>
</div>
)
}
(App.css)
.black-nav {
background : black;
width : 100%;
display : flex;
color : white;
padding : 20px;
}
CSS 스타일은 App.css 파일 열어서 집어넣으면 됩니다.
저장 잘 하면 검은색 상단메뉴가 생성됩니다.
아이잘했어요
JSX 문법 1. html에 class 넣을 땐 className
잘보면 평소에 짜던 html/css와 다른 부분이 있습니다.
스타일을 주기 위한 class명을 넣을 때 class=” “ 가 아니라 className=” “ 이렇게 쓰는 부분이 좀 다른데
왜냐면 실은 App.js에 짜고 있는건 html이 아니라 JSX라고 부르는 이상한 언어라서 그렇습니다.
원래 리액트환경에서 <div>하나 만들고 싶으면 자바스크립트로
React.createElement(‘div’, null)
이딴 식으로 어렵게 코드짜야합니다.
근데 그러면 유저들 다 도망가기 때문에 JSX라는 언어를 대신 사용합니다.
JSX는 html과 사용방식은 비슷합니다.
근데 JSX는 일종의 자바스크립트라서
자바스크립트에서 사용하는 예약어인 class라는 키워드를 막 사용하시면 안됩니다.
그래서 class=” “ 넣고 싶으면 className이라고 써야합니다.
이것이 JSX 다루는 첫째 문법이고 외우고 지나가도록 합시다.
JSX 문법 2. 변수를 html에 꽂아넣을 때는 {중괄호}
자바스크립트 변수같은 곳에 있던 자료를
html 중간에 꽂아서 보여주고 싶을 때가 많습니다.
어떻게 하는지 알아봅시다.
function App(){
let post = '강남 우동 맛집';
return (
<div className="App">
<div className="black-nav">
<div>블로그임</div>
<div>여기에 저 변수에 있던거 꽂고 싶으면?</div>
</div>
</div>
)
}
일단 위에 post라는 변수를 만들어서 잠깐 문자를 저장해놨습니다.
변수가 뭐냐고요?
변수는 길고 복잡한 자료를 잠깐 한 단어에 저장해서 쓸 수 있는 고마운 문법이고 var let const 키워드로 아무데나 만들면 됩니다.
아무튼 저 let post 안에 있던 자료를 <div>안에 꽂아넣고 싶으면 어떻게하죠?
옛날 자바스크립트 문법을 쓴다면 document.getElementById().innerHTML = ?? 이런 식이었겠지만
리액트에서는 더 쉽게 데이터를 꽂아넣을 수 있습니다.
function App(){
let post = '강남 우동 맛집';
return (
<div className="App">
<div className="black-nav">
<div>블로그임</div>
<div>{ post }</div>
</div>
</div>
)
}
중괄호안에 데이터바인딩하고 싶은 변수명만 담으시면 됩니다.
그럼 미리보기화면에서
<div>강남 우동 맛집</div>
요게 출력됩니다.
틀딱개발자들은 여기서 매우 편리함을 느낍니다. 여러분도 뭔가 느끼는척 하십시오
function App(){
var data = 'red';
return (
<div className="App">
<div className="black-nav">
<div>개발 blog</div>
<div className={data}>안녕하세요</div>
</div>
</div>
)
}
온갖 곳에 {} 중괄호를 열어서 변수들을 집어넣을 수 있습니다.
href, id, className, src 등 여러가지 html 속성들에도 가능합니다.
위처럼 쓰면
<div className="red">
이렇게 되겠군요.
참고로 변수에 있던걸 html에 꽂아넣는 작업을 있어보이는 말로 데이터바인딩이라고 합니다.
JSX 문법 3. html에 style속성 넣고싶으면
<div style="color : blue">
이런걸 넣고 싶으면
JSX 상에서는 style={ } 안에 { } 자료형으로 집어넣어야합니다.
<div style={ {color : 'blue', fontSize : '30px'} }> 글씨 </div>
이렇게 넣어야합니다.
{ 속성명 : ‘속성값’ } 이렇게 넣으면 됩니다.
근데 font-size 처럼 속성명에 대쉬기호를 쓸 수 없습니다.
대쉬기호 대신 모든 단어를 붙여써야합니다. 붙여쓸 땐 앞글자를 대문자로 치환해야합니다.
css 파일 열기 귀찮을 때 쓰면 됩니다.
중요한 데이터는 변수말고 state에 담습니다
오늘의 숙제 :
위 사진처럼 블로그 글 목록 3개를 html 레이아웃을 잘 짜서 만들어오시고
제목부분에 들어갈 3개의 데이터는 state에 저장해본 후에 html에 집어넣어보십시오 (데이터바인딩하세요)
변수에 잠깐 데이터 저장하고 html에 {데이터바인딩}도 할 수 있다고 했는데
중요한 데이터를 저장할 땐 변수 대신 state를 만들어씁니다.
state는 왜 쓰는지, state는 어떻게 만들어서 데이터를 저장하는지 알아봅시다.
일단 블로그 글 레이아웃을 만들어봅시다
function App(){
let posts = '강남 우동 맛집';
return (
<div className="App">
<div className="black-nav">
<div>개발 blog</div>
</div>
<div className="list">
<h4>글제목</h4>
<p>2월 17일 발행</p>
</div>
</div>
)
}
(App.css)
div {
box-sizing : border-box
}
.list {
text-align : left;
padding-left : 20px;
border-bottom : 1px solid grey;
}
대충 이렇게 디자인해봤습니다.
그럼 메인페이지에 멋진 블로그 글목록이 하나 생성됩니다.
이제 좀 코드짤 맛이 납니다.
state 만드는 법
이전 강의에서는 그냥 let posts = ‘어쩌구’ 이렇게 변수에 데이터를 저장했었는데
리액트에선 변수 말고 state를 만들어서 데이터를 저장해둘 수 있습니다.
이번엔 state를 이용해 데이터를 잠깐 저장해보도록 합시다.
import { useState } from 'react';
import './App.css'
function App(){
let [a,b] = useState('남자 코트 추천');
let posts = '강남 우동 맛집';
return (
<div className="App">
<div className="black-nav">
<div>개발 blog</div>
</div>
<div className="list">
<h4>글제목</h4>
<p>2월 17일 발행</p>
<hr/>
</div>
</div>
)
}
맨 윗줄에 import {useState} from ‘react’ 하고
원하는 곳에서 useState(‘보관할 자료’) 쓰면 state에 자료를 잠깐 저장할 수 있습니다.
그리고 저장한 자료를 나중에 쓰고 싶으면
let [a,b] = useState(‘남자 코트 추천’);
a 자리에 state 이름을 자유롭게 작명한 다음 나중에 자유롭게 사용하면 됩니다.
Spoiler
무슨 문법임”]
자바스크립트 destructuring 문법인데
내가 array 안에 있는 데이터들을 변수로 쉽게 저장하고 싶으면 쓰는 문법입니다.
예를 들어서 [‘Kim’, 20] 이렇게 생긴 array 자료를 만들어놨는데
에서 Kim이랑 20이라는 자료를 각각 변수에 저장하고 싶으면
let array = ['Kim', 20];
let name = array[0];
let age = array[1];
대충 이렇게 해도 되는데
let [name, age] = ['Kim', 20]
요즘 사람은 이렇게 합니다.
그럼 각각 name = ‘Kim’, age = 20 이라는 변수가 생성됩니다.
귀찮게 등호여러번 쓸 필요 없이 왼쪽 오른쪽 형식을 똑같이 맞춰주시면 자동으로 알아서 변수가 생성됩니다.
이게 변수만들 때 쓰는 destructuring 문법입니다.
익숙하지 않아도 리액트 사용을 위해 일단 외우는게 중요합니다.
그래서 리액트로 다시 돌아가서
useState()를 쓰면 그 자리에 [데이터1, 데이터2] 이렇게 생긴 이상한 array가 남습니다.
데이터1 자리엔 ‘남자 코트 추천’같은 자료가 들어있고
데이터2 자리엔 state변경을 도와주는 함수가 들어있습니다.
그 데이터들을 각각 변수로 빼고 싶으면
let [a, b] = useState('남자 코트 추천')
이러면 되는 것일 뿐입니다.
변수명을 약간 더 직관적으로 작명하면
let [글제목, b] = useState(‘남자 코트 추천’); 이렇게 하면 조금 더 직관적으로 이해할 수 있겠군요.
글제목이라는 변수에는 ‘남자 코트 추천’이라는 자료가 들어간댔으니
한번 html에 중괄호로 {글제목} 넣어보십시오. 진짜 나오지 않습니까
function App(){
let [글제목, b] = useState('남자 코트 추천');
let posts = '강남 우동 맛집';
return (
<div className="App">
<div className="black-nav">
<div>개발 blog</div>
</div>
<div className="list">
<h4>{ 글제목 }</h4>
<p>2월 17일 발행</p>
</div>
</div>
)
}
이렇게 짜고 저장해보면 진짜 글제목 부분에 ‘남자 코트 추천’이 나오는군요.
그래서 결론은 리액트에선 일반 변수대신 state 이용해도 자료를 잠깐 저장해둘 수 있다는겁니다.
맘대로 쓰도록 합시다.
변수 말고 state에 데이터 저장해서 쓰는 이유
새로운 문법을 배웠으면 이걸 어디에 쓸 지 생각해봐야합니다.
그걸 알아야 나중에 혼자서 코드짤 때도 자신있게 state를 가져다 쓰는 것임
잘 생각해보면 state도 용도는 그냥 변수랑 똑같습니다. 자료 잠깐 보관하는게 끝인데
그럼 변수 만들어 쓰면 되는거지 왜 굳이 state 만들어쓰냐고요?
state는 변동사항이 생기면 state쓰는 html도 자동으로 재렌더링해줍니다
function App(){
let post = '강남 우동 맛집'
return (
<h4>{ post }</h4>
)
}
▲ let post 변수에 있던걸 {post} 이렇게 데이터바인딩 해놨다고 가정해봅시다.
근데 갑자기 post 변수에 있던걸 ‘강남 우동 맛집’ -> ‘강남 고기 맛집’ 이렇게 바꿨습니다.
그 변경사항도 html에 반영되게 하고 싶으면 어떻게하죠?
직접 여러분이 “변수내용 바뀌었으니까 html도 고쳐주세요” 라고 귀찮게 코드짜면 됩니다.
쌩자바스크립트는 원래 그래야함
function App(){
let [글제목, b] = useState('남자 코트 추천');
return (
<h4>{ 글제목 }</h4>
)
}
▲ 이번엔 state를 하나 만들어서 {글제목} 이렇게 데이터바인딩 해놨다고 가정해봅시다.
근데 갑자기 state에 있던걸 ‘남자 코트 추천’ -> ‘여자 코트 추천’ 이렇게 바꿨습니다.
그 변경사항도 html에 반영되게 하고 싶으면 어떻게 하냐고요?
state자료는 그럴 필요 없습니다. 여러분이 개입 안해도 자동으로 html도 바뀝니다.
state는 변경이 일어나면 state가 포함된 html을 자동으로 재렌더링 해줘서 그렇습니다.
그럼 뭐가 좋겠습니까
그리고 UI 기능 개발도 매우 편리해지고
OT강의에서 설명드렸던 사이트처럼 스무스하게 동작하는 것임
Q. 그럼 블로그 로고 같은 그런 데이터도 state로 만들어두고 {데이터바인딩} 할까요?
그러셔도 됩니다. 하지만 블로그 로고명은 거의 바뀌지 않죠?
바뀌지 않는 데이터들은 state로 굳이 저장할 필요 없습니다.
state의 가장 큰 장점은 state가 변경될 때마다 자동으로 state와 관련된 html이 재렌더링이 된다는 것인데
로고명은 아예 바뀔 일이 없으니 의미가 없겠죠.
state는 상품명, 글제목, 가격 이런것 처럼 자주 변할 것 같은 데이터들을 저장하는게 좋은 관습입니다.
오늘 수업을 빡대가리 레벨로 정리해드리면
자주변경될 것 같은 데이터들은 state에 저장했다가 html에 {데이터바인딩} 해놓으십시오
변경할 일이 없는 데이터들
굳이 html에 표기가 필요없는 데이터들은 그냥 변수에 저장해도 됩니다.
실은 지금은 변수나 state나 별 차이 없어보이는데
다음 시간에 state 데이터를 변경하는 법을 한번 배워서 진짜 앱처럼 스무스하게 바뀌는지 실험해봅시다.
버튼에 기능개발을 해보자 & 리액트 state변경하는 법
오늘의 숙제 :
버튼을 누르면 첫 글 제목이 ‘여자 코트 추천’으로 바뀌는 기능의 버튼을 만들어봅시다.
버튼에 기능개발을 해보도록 합시다.
버튼을 눌렀을 때 자바스크립트를 실행시키고 싶으면 어떻게 해야하는지,
그리고 state를 수정하려면 어떻게 해야하는지 알아봅시다.
저번시간 숙제는
function App(){
let [글제목, b] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<div className="App">
<div className="black-nav">
<div>개발 blog</div>
</div>
<div className="list">
<h4>{ 글제목[0] }</h4>
<p>2월 17일 발행</p>
</div>
<div className="list">
<h4>{ 글제목[1] }</h4>
<p>2월 17일 발행</p>
</div>
<div className="list">
<h4>{ 글제목[2] }</h4>
<p>2월 17일 발행</p>
</div>
</div>
)
}
useState() 3번 써도 state 3개 만들 수 있는데
그게 귀찮으면 array자료를 이용하면 됩니다.
한 곳에 여러개의 문자를 집어넣고 싶으면 [ ] 대괄호안에다가 문자들 끼워넣고 콤마로 구분해주면 됩니다.
그걸 array자료라고 부릅니다.
그래서 {글제목} 이렇게 쓰면 [‘남자코트 추천’, ‘강남 우동맛집’, ‘파이썬 독학’] 이거 남음
array자료에서 원하는거 하나만 뽑고 싶으면
array이름[0] 이러면 왼쪽에서 부터 0번째 자료가 나옵니다
array이름[1] 이러면 왼쪽에서 부터 1번째 자료가 나옵니다
진짜임 확인해보셈
터미널 / 브라우저 콘솔창에 warning이 뜨는 이유
개발하다보면 에러메세지는 터미널이나 브라우저 개발자도구에 뜬다고 했는데
간혹 노란색 warning 메세지가 등장하는 경우가 있습니다.
빨간 error는 해결해야하지만 warning은 개무시해도 됩니다.
대부분 eslint라는 친구가 잘못된 코딩관습 교정해주는건데
“변수만들었는데 안쓰고 있네요 지우는게 어떰”
이런 식의 잔소리를 warning 으로 띄워줍니다.
초보때는 이런거 지키는거 보다 코드짜보고 실행하는게 중요해서
/*eslint-disable*/
이라는 주석을 js 파일 최상단에 추가해주면 eslint 기능을 잠시 끌 수 있습니다.
좋아요 버튼 만들기
버튼을 누르면 좋아요 갯수가 1씩 증가하는 기능을 만들어봅시다.
그래서 일단 html 레이아웃이 필요할 것 같아서 이렇게 만들면 될듯요
<h4> { 글제목[0] } <span>👍</span> 0 </h4>
미리보기 띄워보면 좋아요 버튼과 갯수가 잘 나오는군요.
여기서 이제 좋아요 갯수에 좀 주목을 해보도록 합시다.
지금은 0이라고 하드코딩 해놨는데, 이러면 안될 것 같습니다.
저번시간에
“자주 바뀔 것 같은 html 내용은 state로 저장했다가 데이터바인딩하세요”
라고 배웠던 기억이 나기 때문에 그렇게 해보도록 합시다.
좋아요 갯수를 state로 만들어보십시오.
state 만들어보셨습니까
function App(){
let [따봉] = useState(0);
return (
<h4> { 글제목[0] } <span>👍</span> { 따봉 }</h4>
)
}
그냥 useState() 쓰고 왼쪽에 작명만 잘하면 state 만들기 끝입니다.
useState() 왼쪽에 작명은 2개 해야하지만 귀찮으면 저처럼 1개만 해도 됩니다.
onClick 사용법
이제 버튼을 누르면 따봉이라는 state를 1 증가시키면 원하던 기능완성인데
그 전에 알아야할게 하나 있습니다.
어떤 html을 클릭시 원하는 코드 실행하는 법을 알아봅시다.
<div onclick="실행할 자바스크립트~~~">
일반 html 파일에선 이렇게 하면 됩니다.
<div onClick={실행할함수}>
JSX에서는 이렇게 합니다.
Click이 대문자인거
{} 중괄호 사용하는거
그냥 코드가 아니라 함수를 넣어야 잘 동작한다는거
를 기억해주십시오.
onClick={ } 안에 함수를 적는게 뭔소리냐면
onClick={} 안에는 어디서 만든 함수명을 적거나 아니면 함수 하나를 바로 만들어서 집어넣어주시면 됩니다.
함수가 뭐냐고요?
함수는 그냥 긴 코드를 짧은 단어 하나로 축약해주는 문법입니다.
function 작명(){ 긴코드 } 이렇게 하면 함수하나 만들 수 있습니다.
function App(){
function 함수임(){
console.log(1)
}
return (
<div onClick={함수임}> 안녕하세요 </div>
)
}
그래서 이러면 div>를 클릭시 함수안에 있던 자바스크립트가 실행됩니다.
이게 리액트에서 어떤 html 요소 클릭시 원하는 코드실행하는 법입니다.
근데 함수 만드는게 귀찮으면
<div onClick={ function(){ 실행할코드 } }>
<div onClick={ () => { 실행할코드 } }>
이렇게 함수를 그 자리에서 직접 만들어버려도 가능합니다.
Q. 함수만들 때 작명안해도 되나요?
A. 나중에 다시 안쓸거면 작명안해도 됩니다.
참고로 () => {} 이 코드도 function (){} 이것이랑 거의 똑같은 기능을 하는 함수만들기 문법입니다.
이뻐보이면 쓰셈
(매우중요) state 변경하는 법
아무튼 좋아요 버튼 누르면 따봉이라는 state를 +1 해주고 싶으면 코드 어떻게 짜죠?
그냥 여러분 잘하는 간단한 자바스크립트 문법 쓰면 됩니다.
function App(){
let [ 따봉 ] = useState(0);
return (
<h4> { 글제목[0] } <span onClick={ ()=>{ 따봉 = 따봉 + 1 } } >👍</span> { 따봉 }</h4>
)
}
변수에 +1 해주고 싶으면 변수 = 변수+1 해주면 끝입니다.
근데 안타깝게도 저건 변수가 아니라 state입니다.
state는 state변경함수를 써서 state를 변경해야합니다.
안그러면 큰일남 (html 재렌더링 안됨)
let [ 따봉, 따봉변경 ] = useState(0);
state만들 때 2개까지 작명할 수 있댔는데
두번째 작명한건 state 변경을 도와주는 함수입니다.
그거 써야 state 변경이 가능합니다.
사용법은
따봉변경(새로운state)
이렇게 쓰면 됩니다.
왜냐면 state 변경함수는 ( ) 안에 넣은걸로 state를 갈아치워주는 함수라 그렇습니다.
따봉변경(1) 이라고 사용하면 따봉이라는 state가 1로 변경됩니다.
따봉변경(100) 이라고 사용하면 따봉이라는 state가 100으로 변경됩니다.
알겠죠? 따봉변경( 따봉 = 따봉 + 1 ) 이딴거 안됩니다. 깔끔하게 새로운 state만 집어넣으시면 됩니다.
좋아요를 눌렀을 때 따봉이라는 state를 1 증가하려면
지금까지의 정보를 바탕으로 빨리 혼자 짜보십시오.
저는 이렇게 했는데
function App(){
let [ 따봉, 따봉변경 ] = useState(0);
return (
<h4> { 글제목[0] } <span onClick={ ()=>{ 따봉변경(따봉 + 1) } } >👍</span> { 따봉 }</h4>
)
}
따봉이라는 기존 state에 1을 더한 값을 따봉변경 함수에 집어넣었습니다.
그럼 버튼을 누를 때 마다 그 값으로 대체됩니다.
진짜 누르니까 1씩 증가하네요
오늘 배운 내용 정리하면
클릭시 뭔가 실행하고 싶으면 onClick={함수} 이렇게 이벤트 핸들러를 달아서 사용합니다.
state를 변경하시려면 state 변경함수를 꼭 이용하십시오.
state변경함수는 ( ) 안에 입력한걸로 기존 state를 갈아치워줍니다.
중요하니 외워둬야합니다.
array, object state 변경하는 법
일단 글수정 버튼 만들기
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{ ??? } }> 수정버튼 </button>
)
}
대충 아무데나 버튼하나 만들고 이거 누르면 첫 글이 수정되는 기능을 만들어봅시다.
저기 물음표안에 뭘 넣어야하죠?
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{
글제목변경(['여자코트 추천', '강남 우동맛집', '파이썬 독학'])
} }> 수정버튼 </button>
)
}
이러면 숙제 끝입니다. 버튼누르면 첫 글제목 바뀜
state 변경함수는 ( ) 안에 넣은걸로 기존 state를 갈아치워주니까 저렇게 집어넣으면 됩니다.
Q. 글제목변경(‘여자코트 추천’) 이건 왜 안됩니까
A. 기존 state를 갈아치워준다니께요
[‘남자코트 추천’, 강남 우동맛집’, ‘파이썬 독학’] 이걸
[‘여자코트 추천’, 강남 우동맛집’, ‘파이썬 독학’] 이걸로 바꾸고 싶으면
[‘여자코트 추천’, 강남 우동맛집’, ‘파이썬 독학’] 이걸 state변경함수에 넣어야지 글 하나만 넣으면 되겠습니까
약간 프로그래머 스타일로 다시만들어보면
지금 코드는 확장성이 부족합니다.
[ ] 안에 글이 3개밖에 없어서 망정이지 글이 100개 들어있으면 어쩔 것임
onClick 안의 코드도 매우 길어지겠군요.
그러니까 기존 state를 다 복붙하지말고
기존 state를 첫 글만 살짝 바꿔서 state변경함수에 집어넣는 식으로 개발해봅시다.
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{
글제목[0] = '여자코트 추천';
글제목변경(글제목)
} }> 수정버튼 </button>
)
}
이래도 됩니다.
array 자료안의 X번째 항목을 변경하고 싶으면
array자료[X] = ‘바꿀값’ 이렇게 하면 됩니다.
그래서 자료를 바꾸고 저기 state변경함수에 집어넣은 겁니다.
근데 이런거보다 더 나은 방법이 하나 있는데
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{
let copy = 글제목;
copy[0] = '여자코트 추천';
글제목변경(copy)
} }> 수정버튼 </button>
)
}
array, object 자료 다룰 때는 원본 데이터를 직접 조작하는 것 보다는
기존값은 보존해주는 식으로 코드짜는게 좋은관습입니다.
(왜냐면 원본 막 바꿔버렸을 때 갑자기 원본이 필요해지면 어쩔 것임)
그래서 let copy 같은 변수에다가 기존 array를 복사해놓고
그걸 조작하는 식으로 코드짜면 조금 더 안전합니다.
근데 사기인듯 수정버튼 눌러도 안바뀌는데요
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{
let copy = [...글제목];
copy[0] = '여자코트 추천';
글제목변경(copy)
} }> 수정버튼 </button>
)
}
이러면 제대로 동작합니다.
근데 동작원리가 궁금하지않습니까
동작원리같은거 많이 알고 있으면 나중에 혼자 코드짤 때 많은 응용이 가능합니다.
state 변경함수 동작원리
state 변경함수를 쓸 때
기존state === 신규state 이렇게 먼저 검사해봅니다.
그래서 같으면 state 변경을 해주지 않습니다.
그래서 위 코드에서도 글제목변경(copy) 해도
copy라는 변수가 기존state와 같아서 변경을 안해준 것입니다.
Q. 잉 copy라는 변수랑 기존 state랑 안에 있는 자료가 다른데 왜 같다고함
기존 state는 ‘남자코트 추천’
copy에는 ‘여자코트 추천’이 들어있지만
실은 기존state === copy 비교해보면 같다고 나옵니다.
왜냐고요?
array/object 동작원리
- 자바스크립트는 array/object 자료를 하나 만들면
예를 들어서 let arr = [1,2,3] 이렇게 만들면
[1,2,3] 자료는 램이라는 가상공간에 몰래 저장이 되고
let arr 변수엔 그 자료가 어디있는지 가리키는 화살표만 담겨있습니다.
- 그래서 array/object 자료를 복사하면 이상한 일이 일어나는데
예를 들면
let data1 = [1,2,3];
let data2 = data1; //복사문법임
이런 식으로 사용하면 복사가 됩니다.
data1에 있던 자료를 data2에 복사한다는 뜻임
그럼 data2 출력해보면 [1,2,3] 이게 잘 나옵니다.
근데 data1과 data2는 각각 [1,2,3]을 별개로 저장하는게 아니라
data1과 data2는 똑같은 값을 공유합니다.
data1을 변경하면 data2도 자동으로 변경되고 그렇습니다. (충격)
왜냐면 변수에는 화살표만 저장된다니까요
그래서 방금 님들 화살표를 복사한 것임
그래서 data1, data2는 똑같은 화살표를 가지게 됩니다. 같은 자료를 가리킴
- 그래서 같은 화살표를 가지고 있는 변수끼리는
등호로 비교해도 똑같다고 나옵니다.
let data1 = [1,2,3];
let data2 = data1; //복사
data2[0] = 1000; //data2 내부 변경
console.log(data2 === data1) //true 나올듯
그렇습니다.
자세한건 javascript reference data type이라고 검색해보면 추가학습 가능합니다.
let copy = 글제목;
copy[0] = '여자코트 추천';
글제목변경(copy)
그래서 아까처럼 이렇게하면
컴퓨터는 copy와 기존 글제목 state는 똑같다고 생각하기 때문에 (화살표가 똑같아서)
state 변경을 안해줍니다.
let copy = [...글제목];
copy[0] = '여자코트 추천';
글제목변경(copy)
이러면 잘됩니다. 화살표가 달라지는 문법이라 그렇습니다.
저기요 점3개 뭐임
spread operator 라고하는 문법인데
array나 object 자료형 왼쪽에 붙일 수 있으며
뜻은 별거없고 괄호를 벗겨주세요~ 라는 뜻입니다.
…[1,2,3] 이렇게 쓰면
그 자리에 1,2,3 이 남습니다. 걍 괄호 벗기기용 연산자입니다.
근데 두번째 용도도 있는데 array나 object 자료형을 복사할 때 많이 사용합니다.
let data1 = [1,2,3];
let data2 = [...data1];
console.log(data1 === data2) //false 나올듯
그냥 data1에 있던 자료들을 괄호 벗긴담에 다시 array로 만들어주세요~ 라고 사용하면
화살표가 달라집니다. 새로운 array로 인식해서요.
그래서 그렇게 하면 화살표가 다른 완전 독립적인 array 복사본을 생성해줄 수 있습니다.
object 자료형도 마찬가지입니다.
그리고 독립적인 사본을 shallow copy 아니면 deep copy 라고 합니다.
오늘의 정리
리액트에서 array/object state를 수정하고 싶으면
독립적인 카피본을 만들어서 수정하는게 좋습니다.
[…기존state]
{…기존state}
이렇게 하면 독립적인 카피가 하나 생성됩니다.
응용문제 : 가나다순 정렬버튼과 기능 만들기
버튼누르면 글제목이 가나다순으로 정렬되는 기능을 만들어봅시다.
힌트를 드리자면
html을 어떻게 정렬할까 고민안해도 되고 글제목 state를 가나다순으로 정렬만 하면 됩니다.
왜냐면 state 변경하면 관련된 html은 자동으로 재렌더링 되니까요
Q. 전 array자료 정렬하는 법을 모르는데요
A. 모르는건 구글찾아봐야지 생각한다고 나오지 않습니다
답인데 보면 안됩니다
function App(){
let [글제목, 글제목변경] = useState( ['남자코트 추천', '강남 우동맛집', '파이썬 독학'] );
return (
<button onClick={ ()=>{
let copy = [...글제목];
copy.sort();
글제목변경(copy)
} }> 정렬버튼 </button>
)
}
버튼 아무데나 만들고 저렇게 코드짰습니다.
이제 누르면 정렬될듯
따라적는건 학습이 아니라 타자연습일 뿐입니다.
Component : 많은 div들을 한 단어로 줄이고 싶으면
오늘은 모달창처럼 뜨는 상세페이지를 한번 만들어보면서
Component 문법을 알아봅시다.
상세페이지 겸 모달창 UI를 하나 만들어봅시다
일단 html css 레이아웃 디자인부터 해봅시다.
<div className="modal">
<h4>제목</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
.modal{
margin-top : 20px;
padding : 20px;
background : #eee;
text-align : left;
}
당연히 css 코드는 css 파일에 넣어야합니다.
모달창 겸 상세페이지 완성 끝
return(
<div></div>
<div></div>
)
근데 html 코드짤 때 유의점이 있는데
return ( ) 안에 두개의 html 태그 나란히 적기 이런거 안됩니다.
return ( ) 내부는 하나의 태그로 시작해서 하나의 태그로 끝나야합니다.
return(
<div>
<div></div>
<div></div>
</div>
)
그래서 굳이 div> 두개를 나란히 적고 싶으면 저렇게 하나의 div로 또 감싸거나 해야합니다.
의미없는 div 쓰기 싫으면 <> </> 이걸로 감싸도 됩니다.
fragment 문법이라고 합니다.
복잡한 html을 한 단어로 치환할 수 있는 Component 문법
리액트는 긴 HTML을 한 단어로 깔끔하게 치환해서 넣을 수 있는 문법을 제공합니다.
Component라고 합니다.
이걸 이용하면 함수 만들듯, 변수 만들듯 HTML을 깔끔하게 한 단어로 치환해서 원하는 곳에 꽂아넣을 수 있습니다.
우리 방금 만든 모달창도 깔끔하게 한 단어로 치환해봅시다.
function App (){
return (
<div>
(생략)
<Modal></Modal>
</div>
)
}
function Modal(){
return (
<div className="modal">
<h4>제목</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
▲ 이렇게 하시면 원하는 HTML을 한 단어로 줄일 수 있습니다.
줄이는 법은
function을 이용해서 함수를 하나 만들어주고 작명합니다.
그 함수 안에 return () 안에 축약을 원하는 HTML을 담으면 됩니다.
그럼 원하는 곳에서 <함수명>함수명> 사용하면 아까 축약한 HTML이 등장합니다.
이렇게 축약한 HTML 덩어리를 Component 라고 부릅니다.
앞으로 HTML 깔끔하게 축약해서 쓰고싶으면 Component 이런 식으로 많이 만들어 쓰십시오.
div> 뭉텅이보다 깔끔하게 Modal> 이렇게 되어있으니
남이 봤을 때 & 미래의 내가 봤을 때 레이아웃을 바로 파악이 가능하니 나중에 관리하기도 좋겠죠?
Component 만들 때 주의점
component 작명할 땐 영어대문자로 보통 작명합니다.
return () 안엔 html 태그들이 평행하게 여러개 들어갈 수 없습니다.
function App(){} 내부에서 만들면 안됩니다.
왜냐면 function App(){} 이것도 다시보니 컴포넌트 생성문법이죠?
component 안에 component 를 만들진 않습니다.
- <컴포넌트>컴포넌트>
이렇게 써도 되고 <컴포넌트>컴포넌트> 이렇게 써도 됩니다.
arrow function 써도 됩니다
function Modal(){
return ( <div></div> )
}
let Modal = () => {
return ( <div></div>)
}
함수 만드는 문법이 하나만 있는게 아니라 저렇게 써도 됩니다.
let 대신 const 변수 쓰는 사람들도 있습니다.
마음에 드는거 씁시다.
어떤 HTML들을 Component 만드는게 좋을까
기준은 없습니다만 관습적으로 어떤 부분을 주로 Component화 하냐면
사이트에 반복해서 출현하는 HTML 덩어리들은 Component로 만들면 좋습니다.
내용이 매우 자주 변경될 것 같은 HTML 부분을 잘라서 Component로 만들면 좋습니다.
다른 페이지를 만들고 싶다면 그 페이지의 HTML 내용을 하나의 Component로 만드는게 좋습니다.
또는 다른 팀원과 협업할 때 웹페이지를 Component 단위로 나눠서 작업을 분배하기도 합니다.
님들 함수문법 언제씁니까
- 긴 코드 축약할 때 2. 다른 곳에서 코드 재사용할 때 3. 복잡한 코드를 작은 기능으로 나눌 때 쓰지 않습니까
컴포넌트는 그냥 함수 문법이랑 똑같아서 용도도 똑같습니다.
Component의 단점
일단 HTML 깔끔하게 쓰려고 Component를 수백개 만들면 그것 만으로도 관리가 힘듭니다.
예를 들어서 function Modal 안에서 글제목 state를 쓰고싶어서 {글제목} 이렇게 쓰면 잘 안되는데
왜냐면 당연히 자바스크립트에선
한 function 안에 있는 변수를 다른 function에서 맘대로 쓸 수 없어서 그렇습니다.
props라는 문법을 이용해 state를
props를 배우진 않았지만 듣기만 해도 귀찮죠?
그러니까 리액트 갓 배운 초보처럼 막 온갖 잡다한걸 Component로 쪼개지 말고 꼭 필요한 곳만 Component로 쪼개시길 바랍니다.
리액트 환경에서 동적인 UI 만드는 법 (모달창만들기)
오늘은 모달창 기능을 어떻게 만드는지 알아봅시다.
“제 완벽한 코드 따라치세요 그럼 모달창 완성~~” 식으로 가르치면 저도 편하고 좋지만
그렇게 배우면 평생 모달창밖에 못만드는 것임
“동적인 UI 알아서 만드는 3-step” 을 알려드릴테니까 이거 가지고 알아서 혼자 코드짜십시오
리액트에서 동적인 UI 만드는 step
동적인 UI가 뭐냐면 유저가 조작시 형태가 바뀌는
모달창 탭 서브메뉴 툴팁 경고문 등 그런 UI들을 의미합니다.
html css로 미리 UI 디자인을 다 해놓고
UI의 현재 상태를 state로 저장해두고
state에 따라서 UI가 어떻게 보일지 조건문 등으로 작성
이렇게 코드짜면 완성입니다.
그래서 글제목 누르면 전에 만들었던
모달창 기능을 만들어봅시다.
step 1. html css로 미리 디자인해놓기
디자인은 저번시간에 다 만들어놔서 패스해도 될듯
step 2. UI의 현재 상태를 state로 저장
state 하나 만들고
거기에 현재 UI의 상태정보를 저장해두라는 소리입니다.
let [modal, setModal] = useState(false);
저는 modal이라고 작명했습니다.
영어로 작명시 state변경함수는 set을 앞에 붙이는게 관습입니다.
state에 무슨 자료를 넣어야되냐면 정말 맘대로 하면 됩니다.
그냥 현재 모달창의 상태만 표현할 수 있으면 됩니다.
모달창은 열림/닫힘 이 두개 상태밖에 없기 때문에 그거 2종류만 표현할 수 있는 자료형이면 됩니다.
let [modal, setModal] = useState('닫힘');
let [modal, setModal] = useState(0);
‘닫힘’/’열림
0/1
아무렇게나 표현해도 상관없습니다. 저는 true/false로 표현해볼 것임
(true false는 참 거짓을 담을 수 있는 boolean이라는 자료형입니다)
step 3. state에 따라서 UI가 어떻게 보일지 작성
function App (){
let [modal, setModal] = useState(false);
return (
저 state가 true면 <Modal></Modal>
false면 아무것도 보여주지마세요
)
}
이렇게 코드짜라는 소리입니다.
프로그래밍할 때 “이 경우엔 이렇게 해주세요~” 라고 코드짜고 싶으면 if 조건문을 사용합니다.
JSX에서 조건문 쓰는 법
조건문은 if / else 문법을 쓰면 되는데
JSX 안에서는 if else 문법을 바로 사용할 수 없습니다.
써보십시오 글자색도 이상해질걸요
하지만 if 문법 대신 삼항연산자라는건 JSX 중괄호 안에서 사용가능합니다.
조건식 ? 조건식 참일 때 실행할 코드 : 조건식 거짓일 때 실행할 코드 이렇게 if문 대신 쓸 수 있는 문법이 삼항연산자입니다.
3 > 1 ? console.log(‘맞음’) : console.log(‘아님’) 예를 들어 이렇게 쓰면 3 > 1 이게 참이기 때문에 ‘맞음’이 출력됩니다.
그래서 아까 모달창으로 돌아가서
저 state가 true면
false면 아무것도 보여주지마세요~
라고 코드짜고 싶으면 어떻게 할까요?
function App (){
let [modal, setModal] = useState(false);
return (
<div className="app">
(생략)
{
modal == true ? <Modal></Modal> : null
}
</div>
)
}
이렇게 코드짜면 됩니다.
null은 그냥 아무 html도 남기기 싫을 때 쓰는 자료입니다. null은 텅 비었다는 뜻임
이제 3-step 끝입니다.
글제목 누르면 모달창을 띄우고 싶어요
지금은 모달창이 안보입니다.
왜냐면 state 기본값이 false였고, false일 경우엔
그럼 이제 글제목을 클릭하면 모달창이 보이게 만들고 싶으면 어떻게 하죠?
어떻게 코드짜야합니까.
힌트는 여러분이
“글제목 누르면 모달 html을 보이게 해주세요” 라고 코드를 짜는게 아니라
“글제목 누르면 state를 조절해주세요” 라고 코드짜면 됩니다.
왜냐면 state 바뀌면 html은 알아서 자동으로 재렌더링됩니다.
혼자 한번 해보시고 펼쳐보십시오
function App (){
let [modal, setModal] = useState(false);
return (
<div>
(생략)
<button onClick={ ()=>{ setModal(true) } }> {글제목[0]} </button>
{
modal == true ? <Modal></Modal> : null
}
</div>
)
}
글제목 누르면 modal이라는 state를 true로 바꿔달라고 코드짰습니다.
그럼 이제 제목누르면 모달창 보이는 것임
그래서 리액트에서 UI만드는 과정을 비유하면
스위치와 전등만드는거랑 비슷하다고 보면 됩니다.
일단 전등이쁘게 달아놓고
스위치랑 연결하고
스위치를 on으로 놓으면 불이 켜지고 off로 놓으면 불이 꺼지도록
만들어놓는 겁니다.
그리고 나중에 필요하면 스위치 조작만 하면 되는 것임
스위치는 state, 전등은
그래서 예전 쌩자바스크립트로 UI 만드는 것과는 약간 방식이 다릅니다.
쌩자바스크립트는 귀찮게 html을 조작해야했는데
리액트환경에선 html을 직접 조작하지 않습니다.
그래서 예전 방식에 익숙한 사람이라면 정신개조를 좀 해야함
오늘의 숙제 :
글제목 한번 더 누르면 모달창이 닫혀야합니다.
어떻게 코드를 짜면 될까요?
최소 1일은 투자해보고 정 안되면 펼쳐봅시다
이번만 봐드립니다 다음은 없음
글제목 클릭시
지금 state가 true면 setModal(false)
지금 state가 false면 setModal(true)
이런 코드를 실행하면 됩니다.
if 조건문이나 삼항연산자나 그런거 쓰면 될듯요
이걸 몰랐다면 리액트 잘하고 못하고의 문제가 아니라 프로그래밍하는 법을 안배워서 그럴 뿐입니다.
실은 리액트 문법보다 혼자서 알아서 프로그래밍하는 법 같은게 더 중요함
function App (){
let [modal, setModal] = useState(false);
return (
<div>
(생략)
<button onClick={ ()=>{ setModal(!modal) } }> {글제목[0]} </button>
{
modal == true ? <Modal></Modal> : null
}
</div>
)
}
아니면 간단하게 setModal(!modal) 이래도 됩니다.
느낌표가 뭐냐면
느낌표 우측 자료를 반대로 바꿔줍니다.
!true는 출력해보면 false입니다.
!false는 출력해보면 true입니다.
그래서 저렇게 써도 가능할듯요
map : 많은 div들을 반복문으로 줄이고 싶은 충동이 들 때
오늘의 숙제 :
지금 좋아요버튼 누르면 모든 글의 좋아요 갯수가 동시에 증가하고 있습니다.
각각 개별적으로 좋아요 갯수를 기록하고 싶으면 어떻게 코드짜야할까요?
똑같은 html이 반복적으로 출현하면
반복문을 이용해서 쉽게 똑같은 html을 생성할 수도 있습니다.
안타깝게도 for 반복문은 JSX 중괄호 안에서 사용할 수 없어서 map() 을 대신 사용합니다.
자바스크립트 map 함수 쓰는 법
모든 array 자료 우측엔 map() 함수를 붙일 수 있습니다.
자바스크립트 기본함수 같은건데 용도를 알아봅시다.
var 어레이 = [2,3,4];
어레이.map(function(){
console.log(1)
});
기능 1. array에 들어있는 자료갯수만큼 그 안에 있는 코드를 반복실행해줍니다.
저러면 진짜로 console.log(1) 3번 실행됨
var 어레이 = [2,3,4];
어레이.map(function(a){
console.log(a)
});
기능 2. 콜백함수에 파라미터 아무렇게나 작명하면
그 파라미터는 어레이 안에 있던 모든 자료를 하나씩 출력해줍니다.
(그냥 소괄호안에 있는 함수를 콜백함수라고 합니다)
저러면 진짜로 2, 3, 4가 콘솔창에 출력됨
var 어레이 = [2,3,4];
var newArray = 어레이.map(function(a){
return a * 10
});
console.log(newArray)
기능3. return 오른쪽에 뭐 적으면 array로 담아줍니다.
그리고 map() 쓴 자리에 남겨줍니다.
그래서 변수에 담아서 출력해봤더니 진짜로 array에 담아주긴 하는군요
newArray는 [20, 30, 40] 이 출력됩니다.
JSX 안에서 html을 반복생성하고 싶으면
리액트 중괄호안에서 html을 반복생성하고 싶으면 아까 배운 map을 이용해도 됩니다.
function App (){
return (
<div>
{
[1,2,3].map(function(){
return ( <div>안녕</div> )
})
}
</div>
)
}
▲ 이렇게 쓰면
<div>안녕</div>
이 3개나 생성됩니다.
진짜인지 미리보기화면에서 확인해봅시다.
대충 원리설명은
우선 [1, 2, 3] 에다가 map을 붙였으니 그 안의 자료 갯수만큼 map 내부 코드를 실행해줍니다.
근데 안에
return <div>안녕</div>
이게 있군요
그럼
<div>안녕</div>
이걸 array에 담아줍니다. 3번이나요
[ <div>안녕</div>, <div>안녕</div>, <div>안녕</div> ]
▲ 그럼 이게 남습니다.
근데 이걸 html로 미리보기 띄워볼 땐
<div>안녕</div>
<div>안녕</div>
<div>안녕</div>
이렇게 보입니다.
그래서 map을 써도 html 반복생성이 가능한 것임
예전에 만들었던 글제목 3개도 반복문으로 축약 가능할듯
지금 우리 프로젝트를 잘 보면
<div className="list">
이 부분이 3번이나 반복되고 있습니다.
이것도 map 반복문으로 축약하면 코드 양이 더 줄어들지 않을까요.
function App (){
return (
<div>
(생략)
{
글제목.map(function(){
return (
<div className="list">
<h4>{ 글제목[0] }</h4>
<p>2월 18일 발행</p>
</div> )
})
}
</div>
)
}
▲ 이렇게 하면 글제목이 3개 생성됩니다.
(글제목이라는 state도 array자료라서 map 붙일 수 있습니다)
그래서 오늘의 결론은
비슷한 html 여러개 필요하면 map() 안에 담으면 됩니다.
근데 반복된 HTML에 각각 다른 제목을 부여하고 싶다면
지금 위의 코드를 잘 보시면
<h4>{ 글제목[0] }</h4>
이라는 것만 3번 반복되고 있습니다.
그래서 같은 제목만 3번 출현하는듯요
그게 아니라 반복문이 돌 때마다
<h4>{ 글제목[0] }</h4>
<h4>{ 글제목[1] }</h4>
<h4>{ 글제목[2] }</h4>
이런 데이터가 들어가게 만들고 싶으면 어떻게 코드를 수정해야할까요?
그것은 아까 map 함수의 사용법을 잘 상기시켜보면 알 수 있습니다.
function App (){
return (
<div>
(생략)
{
글제목.map(function(a){
return (
<div className="list">
<h4>{ a }</h4>
<p>2월 18일 발행</p>
</div> )
})
}
</div>
)
}
▲ 이렇게 하면 각각 다른 글제목이 3개 생성됩니다. 성공
왜 그런지 모르겠어요
a라는 파라미터는
map이 반복될 때마다 array자료 안에 있던 하나하나의 데이터들을 의미한다고 했습니다.
그래서 a 출력해보면
반복문이 돌 때 마다 차례로 ‘남자 코트추천’ ‘강남 우동 맛집’ 이런 데이터들이 된다는 소리입니다.
그걸 그냥 h4> 안에 집어넣었을 뿐입니다.
function App (){
return (
<div>
(생략)
{
글제목.map(function(a, i){
return (
<div className="list">
<h4>{ 글제목[i] }</h4>
<p>2월 18일 발행</p>
</div> )
})
}
</div>
)
}
▲ 실은 이렇게 해도 되는데 왜냐면
map(function(a, i){
이렇게 파라미터를 2개까지 작명 가능한데
첫째 파라미터 a는 array안에 있던 자료
둘째 파라미터 i는 0부터 1씩 증가하는 정수
가 되어서 그렇습니다.
i 출력해보면 0 1 2 이런 식으로 나옵니다. 진짜임
전에 만들었던 따봉기능도 추가해보면
function App (){
return (
<div>
(생략)
{
글제목.map(function(a, i){
return (
<div className="list">
<h4 onClick={()=>{ 따봉변경(따봉+1) }}>{ 글제목[i] }</h4>
<p>2월 18일 발행</p>
</div> )
})
}
</div>
)
}
▲ 반복문 안에 있는 html에 onClick 같은거 추가해도 아무런 문제가 없습니다.
근데 약간 문제가 있는데
아무 글제목이나 클릭하면 따봉갯수가 다 똑같이 증가하는군요
그게 싫으면 오늘 숙제로 해결해봅시다.
(참고) map 반복문으로 반복생성한 html엔 key={i} 이런 속성을 추가해야합니다.
<div className="list" key={i}>
그래야 리액트가 div>들을 각각 구분할 수 있어서 그렇습니다.
없으면 워닝띄워줌
(참고) 일반 for 반복문을 쓰고싶다면
html들을 담아둘 array 자료를 하나 만들어줍니다.
일반 for 반복문을 이용해서 반복문을 돌림
반복될 때 마다 array자료에 <div> 하나씩 추가해줍니다.
원하는 곳에서 {array자료} 사용하면 됩니다.
function App (){
var 어레이 = [];
for (var i = 0; i < 3; i++) {
어레이.push(<div>안녕</div>)
}
return (
<div>
{ 어레이 }
</div>
)
}
▲ 예를 들면 이런 식입니다.
이렇게 해도
<div>안녕</div>
이게 3개 출현합니다.
for 문법은 JSX 안에서 사용할 수 없어서 저렇게 바깥에서 쓰면 됩니다.
귀찮으면 map을 씁시다.
오늘의 숙제 :
지금 좋아요버튼을 누를 때 마다 모든 따봉갯수가 똑같이 1 증가하고 있습니다.
각각 개별적으로 증가하게 하려면 어떻게 해야할까요?
(힌트) 지금 잘보면 따봉갯수를 기록할 state가 하나밖에 없어서 그렇습니다.
그걸 모든 글제목들이 가져다 쓰고 있어서 그런 것일 뿐임
답보면 코딩성장판이 닫힙니다
직접 뭐라도 쳐봐야 실력이 늘기 때문입니다.
어려우면 반복문 쓰지 않은 이전강의 코드에서 시작해보십시오 더 쉽습니다.
지금 따봉 기록할 state가 하나라서 그렇습니다.
let [따봉, 따봉변경] = useState(0); let [따봉1, 따봉변경1] = useState(0); let [따봉2, 따봉변경2] = useState(0);
이렇게 3개 만든 다음에 각각 글마다 집어넣어주면 완성입니다.
근데 이렇게 만들면 글이 10개가 있을 경우 10줄 작성할 것입니까
그건 좀 귀찮기 때문에 array자료를 활용해도 됩니다.
let [따봉, 따봉변경] = useState([0,0,0]);
이렇게 array를 이용하면 한 변수에 자료 3개를 저장할 수 있으니까 이래도 됩니다.
{
글제목.map(function(a, i){
return (
<div className="list">
<h4>{ 글제목[i] }
<span onClick={()=>{ ??? }}>👍</span> {따봉[i]}
</h4>
<p>2월 18일 발행</p>
</div> )
})
}
▲ 그럼 따봉을 JSX안에 보여줄 때도 저렇게 보여주면 되겠군요. 일단 보여주는건 성공
근데 onClick안에는 뭐 넣어야합니까?
0번째 좋아요 버튼을 클릭시엔 따봉[0] + 1 을 해야하고
1번째 좋아요 버튼을 클릭시엔 따봉[1] + 1 을 해야하고
2번째 좋아요 버튼을 클릭시엔 따봉[2] + 1 을 해야하고
그러면 됩니다.
근데 따봉이라는건 state니까 state 변경함수 써야합니다. 그리고 array자료니까 array 자료변경시 주의점도 신경써야겠군요.
<h4>
{ 글제목[i] }
<span onClick={()=>{
let copy = [...따봉];
copy[i] = copy[i] + 1;
따봉변경(copy)
}}>👍</span> {따봉[i]}
</h4>
state가 array자료일 경우 복사부터 하고
그거 수정하면 된다고 해서 그렇게 했습니다.
Q. 저 코드 너무 어려워요
원래 남의 코드 읽는건 세계최고로 어려운 일이라 직접 해보는게 더 이해빠름
어려우면 map 반복문 쓰지 않은 이전 강의 코드에서 해보십시오 더 쉽습니다.
자식이 부모의 state 가져다쓰고 싶을 때는 props
오늘의 숙제 :
모달창안에 글수정버튼 만들고
그거 누르면 첫 글제목이 ‘여자코트 추천’으로 바뀌는 기능을 만들어봅시다.
자식 컴포넌트가 부모 컴포넌트에 있던 state를 쓰고 싶으면
그냥 쓰면 안되고 props로 전송해서 써야합니다.
뭔소린지 알아봅시다.
일단 모달창 잘 띄우고 시작해봅시다.
Modal>안에 글제목 state 가 필요한데
저번에 만든 Modal> 내부에 글제목 state를 집어넣고 싶으면 어떻게하죠?
예를 들면 이렇게 하면 될듯요
function App (){
let [글제목, 글제목변경] = useState(['남자코트 추천', '강남 우동맛집', '파이썬독학']);
return (
<div>
<Modal></Modal>
</div>
)
}
function Modal(){
return (
<div className="modal">
<h4>{ 글제목[0] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
▲ 하지만 제대로 실행되지 않습니다.
‘글제목’이라는 변수가 define 되지 않았다고 에러가 뜹니다.
왜냐면 글제목이라는 state 변수는 function App()에 있지 function Modal()에 없으니까요.
자바스크립트에선 다른 함수에 있는 변수를 마음대로 가져다쓸 수 없습니다.
근데 컴포넌트 2개가 부모/자식 관계인 경우엔 가능합니다.
(다른 컴포넌트 안에 있는 컴포넌트를 자식컴포넌트라고 부릅니다)
부모 컴포넌트의 state를 자식 컴포넌트로 전송해줄 수 있습니다. 그럼 자식도 사용가능
전송시엔 props라는 문법을 사용합니다.
props로 부모 -> 자식 state 전송하는 법
2개의 step을 따라주시면 됩니다.
자식컴포넌트 사용하는 곳에 가서 <자식컴포넌트 작명={state이름} />
자식컴포넌트 만드는 function으로 가서 props라는 파라미터 등록 후 props.작명 사용
하지만 이론만 설명하면 이해가 되지 않으니 예시를 보아야합니다.
글제목이라는 부모 컴포넌트의 state를 자식 컴포넌트
function App (){```
let [글제목, 글제목변경] = useState(['남자코트 추천', '강남 우동맛집', '파이썬독학']);
return (
<div>
<Modal 글제목={글제목}></Modal>
</div>
)
}
function Modal(props){
return (
<div className="modal">
<h4>{ props.글제목[0] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
자식컴포넌트 사용하는 곳에 가서 <자식컴포넌트 작명={state이름} />
자식컴포넌트 만드는 곳에 가서 props라는 파라미터 등록 후 props.작명 사용하면 됩니다.
props 전송문법은 중요하니 외워두도록 합시다.
(참고1) props는 <Modal 이런거={이런거} 저런거={저런거}> 이렇게 10개 100개 1000개 무한히 전송이 가능합니다.
(참고2) 꼭 state만 전송할 수 있는건 아닙니다.
<Modal 글제목={변수명}>
일반 변수, 함수 전송도 가능하고
<Modal 글제목="강남우동맛집">
일반 문자전송은 중괄호 없이 이렇게 해도 됩니다.
▲ 자식 → 부모 패륜방향 전송은 불가능합니다.
▲ 옆집 컴포넌트로의 불륜전송도 불가능합니다.
props는 함수 파라미터 문법이랑 똑같습니다
함수에 파라미터같은거 왜 넣죠?
자바스크립트 기초강의에서는
“함수 하나로 다양한 기능을 사용하기 위해서 쓰는게 파라미터 문법” 이랬습니다.
props도 실은 파라미터랑 똑같은 문법입니다.
그래서 이런 식으로 응용도 가능한데
function Modal(props){
return (
<div className="modal" style=>
<h4>{ props.글제목[0] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
갑자기 하늘색 배경의 모달창이 필요하면 저렇게 스타일 넣으면 됩니다.
근데 이번엔 오렌지색 모달창이 필요하면 어떻게합니까?
갑자기 노란색 모달창도 필요하면요?
가장 쉬운 방법은
function Modal2() {}
function Modal3() {}
….
이렇게 컴포넌트를 또 만들어서 각각 배경색을 다르게 만들어도 되겠지만
내용이 똑같은데 배경색만 다르면 굳이 같은 함수 여러개 만들 필요가 없습니다.
function Modal(props){
return (
<div className="modal" style=>
<h4>{ props.글제목[0] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
props.color 이런 식으로 구멍을 뚫어놓으면 이제 컴포넌트 사용할 때
<Modal color={'skyblue'} />
이러면 하늘색 모달창이 생성됩니다.
<Modal color={'orange'} />
이러면 오렌지색 모달창이 생성됩니다.
그래서 비슷한 컴포넌트를 또 만들 필요가 없어지는 것입니다.
그래서 내가 함수 파라미터 문법을 잘 알고 있다면
그런 식으로도 응용가능합니다.
그래서 결론은 자바스크립트 잘해야 리액트를 잘합니다.
props를 응용한 상세페이지 만들기
오늘은 새로운 내용은 없고 지금까지 배웠던 내용들로 재밌는 기능을 만들어봅시다.
지금 글 누르면 모달창이 뜨는데 안에 0번 글제목만 보이고 있습니다.
(안뜨면 뜨게 하십시오)
Q. 지금 누른 글제목이 모달창안에 뜨게 하고 싶으면 어떻게 코드를 짜야할까요?
0번 글을 누르면 0번 글제목이 모달창안에 등장하고
1번 글을 누르면 1번 글제목이 모달창안에 등장하고
그런 식으로 동작하게 만들어봅시다.
다 배운내용이라 강의 듣지말고 알아서 해봅시다.
약간의 힌트는
직접 뭐라도 해보라고 드리는 힌트인데
모달창안의 제목도 일종의 동적인 UI입니다.
동적인 UI 어떻게 만들라고 했습니까
html css로 미리 디자인해놓고
현재 UI의 상태를 state로 만들어두고
state 종류에 따라서 UI가 어떻게 보일지 작성하랬습니다.
그러면 끝임
이제 나중에 필요할 때 스위치 (state) 조작만 하면 됩니다.
- html css로 미리 디자인해놓고
다 한것 같군요 패스합시다
- 현재 UI의 상태를 state로 만들어두고
let [title, setTitle] = useState(0); 그래서 저는 function App(){} 안에 state 하나 만들었습니다.
모달창 안의 글제목은 0번글이 보이거나 1번글이 보이거나 2번글이 보이거나
이런 상태밖에 없어서 그냥 숫자로 표현하고 싶어서 숫자적어놨습니다.
- state에 따라서 UI가 어떻게 보일지 작성
function App (){
let [title, setTitle] = useState(0);
(생략)
}
function Modal(props){
return (
<div className="modal">
<h4>{ 만약에 title == 0이면 0번 글제목 보여주세요~ }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
만약에 title == 0이면 props.글제목[0] 보여주세요~
만약에 title == 1이면 props.글제목[1] 보여주세요~
이렇게 코드짜면 기능완성입니다.
당연히 조건문 같은거 사용하면 됩니다.
function App (){
let [title, setTitle] = useState(0);
(생략)
}
function Modal(props){
return (
<div className="modal">
<h4>{ props.글제목[title] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
근데 이렇게 해도 될듯요
그럼 title이 0이면 props.글제목[0] 보이지 않겠습니까
아무튼 기능완성인데 왜 에러가 나는 것이죠
왜겠습니까
title이라는 state는 부모가 가진 state라서
자식이 사용하고 싶으면 props로 전송해야합니다. 전송하십시오
function App (){
let [title, setTitle] = useState(0);
(생략)
{
modal == true ? <Modal title={title} 글제목={글제목} /> : null
}
}
function Modal(props){
return (
<div className="modal">
<h4>{ props.글제목[props.title] }</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
)
}
props로 전송했습니다. UI 만들기 끝
이제 스위치를 다 만들어놨기 때문에
title이라는 스위치를 0, 1, 2로 바꿔주면 그 때마다 알맞은 글이 모달창에 표시됩니다.
글에 onClick 집어넣으면 끝임
이제 글을 클릭할 때 스위치만 샤샥 바꿔주면 원하는 기능구현 끝입니다.
0번 글을 클릭하면 title이라는 스위치를 0으로 바꿔주고
1번 글을 클릭하면 title이라는 스위치를 1로 바꿔주고
2번 글을 클릭하면 title이라는 스위치를 2로 바꿔주고
그러면 의도한 기능이 완성되겠군요.
근데 지금 글제목들이 map 반복문으로 복잡하게 생성되어있기 때문에
반복문 무서워할까봐 반복문 없앤 버전으로 한번 먼저 시도해봅시다.
function App (){
let [title, setTitle] = useState(0);
return (
<div>
<button onClick={()=>{ ? }}> 0번글 </button>
<button onClick={()=>{ ? }}> 1번글 </button>
<button onClick={()=>{ ? }}> 2번글 </button>
<Modal 어쩌구/>
</div>
)
}
버튼 3개를 만들어봤는데 이걸 각각의 글제목이라고 간주하고 여기에 코드를 짜보도록 합시다.
0번 글을 누르면 title이라는 state를 0으로 바꿔주면 어떻게하죠?
function App (){
let [title, setTitle] = useState(0);
return (
<div>
<button onClick={()=>{ setTitle(0) }}> 0번글 </button>
<button onClick={()=>{ setTitle(1) }}> 1번글 </button>
<button onClick={()=>{ setTitle(2) }}> 2번글 </button>
<Modal 어쩌구/>
</div>
)
}
이러면 될듯요 매우 쉽습니다.
그럼 이제 버튼 누를 때 마다 state가 잘 바뀝니다.
state가 바뀌면 모달창안의 제목도 알아서 잘 바뀌고요.
이제 연습은 끝났고 map 반복문안에 있는 제목도 저거랑 비슷하게 수정하면 될듯요
저는 어떻게 했냐면
function App (){
return (
<div>
{
글제목.map(function(a, i){
return (
<div className="list">
<h4 onClick={()=>{ setModal(true); setTitle(i); }}>{ 글제목[i] }</h4>
<p>2월 18일 발행</p>
</div> )
})
}
</div>
)
}
각각 글제목 누르면 setTitle(i) 해달라고 코드짰습니다.
map 안에서의 i가 뭐였냐면 반복문이 돌 때 마다 0, 1, 2 … 이렇게 증가하는 정수라고 했습니다.
그래서 첫 글제목은 클릭시 setTitle(0) 이 실행될 것이고
둘째 글제목은 클릭시 setTitle(1) 이 실행될 것이고
셋째 글제목은 클릭시 setTitle(2) 이 실행될 것이고
그렇습니다.
아무튼 글제목 누르면 스위치 조작이 잘되고
스위치가 조작되면 모달창 안의 글제목도 알아서 잘 바뀌는군요 성공
input 1 : 사용자가 입력한 글 다루기
리액트에서 유저가 입력한 input 데이터는 어떻게 처리하는지 알아봅시다.
실은 쌩자바스크립트 문법이랑 똑같습니다.
input 태그 사용하기
유저의 입력을 받을 수 있는 박스를 생성하고 싶으면
html에선 다음과 같은 태그들을 이용가능합니다.
<input type="text"/>
<input type="range"/>
<input type="date"/>
<input type="number"/>
<textarea></textarea>
<select></select>
이거 말고도 다양한 종류의 인풋 박스가 많으니 필요할 때 찾아쓰도록 합시다.
input에 뭔가 입력시 코드를 실행하려면
유저가 input에 뭔가 입력시 코드를 실행해주고 싶을 때가 많습니다.
그러고 싶으면 onChange 아니면 onInput 이벤트핸들러를 부착하면 됩니다.
<input onChange={()=>{ 실행할코드 }}/>
onChange, onInput은
input에 유저가 뭔가 입력할 때마다 안에 있는 코드를 실행해줍니다.
진짜인지 console.log(1) 이런거 넣어서 테스트해봅시다.
(참고)
이벤트 핸들러들은 매우 많습니다.
onMouseOver={ } 이건 이 요소에 마우스를 댔을 때 안의 코드를 실행해줍니다.
onScroll={ } 이건 이 요소를 스크롤했을 때 안의 코드를 실행해줍니다.
몇십개 있는데 원하는 이벤트가 있으면 찾아서 사용해봅시다.
input에 입력한 값 가져오는 법
<input onChange={(e)=>{ console.log(e.target.value) }}/>
e라는 파라미터를 추가해주고
e.target.value라고 적으면 현재 < input >에 입력된 값을 가져올 수 있습니다.
콘솔창에 출력해보니 진짜 가져옵니다.
이벤트핸들러에 들어가는 함수에 저렇게 파라미터 e를 추가하면
e는 이벤트 객체 이런 식으로 부르는데
현재 발생하는 이벤트와 관련한 유용한 기능들을 제공하는 일종의 변수입니다.
(작명은 e 말고 자유롭게 해도 됩니다)
e.target 이러면 현재 이벤트가 발생한 곳을 알려주고
e.preventDefault() 이러면 이벤트 기본 동작을 막아주고
e.stopPropagation() 이러면 이벤트 버블링도 막아줍니다. 이거 쓰면 좋아요버튼 누를 때 모달창도 떠버리는 버그 해결가능
사용자가 input에 입력한 데이터 저장하기
사용자가 input에 입력한 데이터는 state 아니면 변수에 저장해서 쓰는게 일반적입니다.
그래야 편리하기 때문에 일단 저장부터 해봅시다.
state 배운 기념으로 state를 사용합시다.
function App (){
let [입력값, 입력값변경] = useState('');
return (
<input onChange={(e)=>{
입력값변경(e.target.value)
console.log(입력값)
}} />
)
}
state를 하나 만들어주고 onChange될 때 마다 state에 e.target.value 넣으라고 코드를 짰습니다.
state에 문자를 저장하고 싶은데 일단 기본값을 뭘 넣을지 모르겠으면 따옴표 2개만 치면 됩니다.
따옴표 2개는 빈문자를 뜻합니다.
이제 입력값이라는 state를 필요한 곳에서 마음대로 사용하면 되겠습니다.
(참고)
근데 위 코드 실행해보면 a를 입력하면 콘솔창에 아무것도 안뜨지 않습니까
aa를 입력하면 a만 콘솔창에 뜨고요.
왜냐면 state 변경함수 특징 때문인데 state 변경함수는 약간 늦게 처리됩니다.
전문용어로 async하게 (비동기적으로) 처리된다고 합니다.
그리고 자바스크립트에선 늦게 처리되는 코드들은 잠깐 제쳐두고 바로 다음줄을 실행해줍니다.
그래서 console.log(입력값) 이게 먼저 실행되어서 저렇게 나오는 것일 뿐입니다.
그냥 실행 순서만 좀 다를 뿐 state변경은 어쨌든 잘 됩니다.
오늘의 숙제 :
- input에 뭐 입력하고 발행버튼누르면
블로그에 글이 하나 추가되는 기능을 만들어보십시오.
- 글마다 옆에 삭제버튼 하나씩 만들어놓고 삭제버튼누르면 글이 없어지는 기능을 만들어보십시오.
(힌트)
html 직접 만질 필요는 없습니다. 지금 글제목 state만 바꾸면 html도 알아서 바뀌지 않겠습니까
array에 자료를 추가하거나 삭제하는 문법은 모르면 구글찾아봐야지 생각한다고 나오는 것은 아닙니다.
input 다루기 2 : 블로그 글발행 기능 만들기
오늘은 새로운 내용은 없고 저번시간 숙제 2개를 풀어보고 지나갑시다.
여러분 코드가 의도대로 잘 동작한다면 맞는 답안이니까 그냥 다음으로 넘어가셔도 무방합니다.
답은 언제나 하나가 아닙니다.
숙제1. 버튼누르면 유저가 입력한 글을 글목록에 추가해주세요
그럼 이렇게 코드짜면 되겠군요
“버튼누르면 유저가 입력한 글 가져와서 그걸로 html을 하나 생성해주세요~”
근데 이건 쌩자바스크립트 방식이고 리액트는 스위치와 전등 만들어놓고 state만 만지면 된다고 했습니다.
“버튼누르면 유저가 입력한 글 가져와서 글제목 state에 넣어주세요”
이렇게 코드짜면 끝입니다.
왜냐면 지금 글제목.map() 이렇게 코드짠 덕분에 글제목 state 갯수에 맞게 html이 알아서 생성되고 있으니까요.
function App (){
let [글제목, 글제목변경] = useState(['남자코트추천', '강남우동맛집', '파이썬독학']);
let [입력값, 입력값변경] = useState('');
return (
<div>
<input onChange={ (e)=>{ 입력값변경(e.target.value) } } />
<button onClick={()=>{
???
}}>글발행</button>
</div>
)
}
▲ 글발행 버튼을 하나 만들었는데 이거 누르면 어떤 코드를 실행하면 될까요?
이제 리액트 기초문법시간이 끝났기 때문에
리액트 지능이 상승할 마지막 기회니까 아직 안해봤다면 직접 해봅시다.
전 이렇게 했는데
function App (){
let [글제목, 글제목변경] = useState(['남자코트추천', '강남우동맛집', '파이썬독학']);
let [입력값, 입력값변경] = useState('');
return (
<div>
<input onChange={ (e)=>{ 입력값변경(e.target.value) } } />
<button onClick={()=>{
let copy = [...글제목];
copy.unshift(입력값);
글제목변경(copy)
}}>글발행</button>
</div>
)
}
발행버튼누르면 글제목state에 유저가 입력한값만 하나 끼워넣으면 됩니다.
버튼누르면 일단 글제목state를 카피부터했습니다. array 형태의 state 조작은 우선 카피부터하면 된댔습니다.
카피한거에 unshift(입력값) 해줬는데 이게 뭐냐면 array자료 맨 앞에 자료추가하는 문법입니다.
그리고 state변경함수 사용했습니다.
그럼 이제 input 태그에 뭐 입력하고 발행버튼 누르면 글이 진짜로 발행되는 것 같은 기능이 완성됩니다.
Q. 저는 state, sprops, component, map 전부 아는데 코드를 못짜겠어요 뭐임?
A. 그것은 리액트를 못하는게 아니라 프로그래밍 기초가 부실할 뿐이니 안심하셔도 됩니다.
Q. 왜 새로고침하면 없어지죠?
원래 브라우저는 새로고침하면 html, js 파일을 다시 읽습니다.
다시 읽으면 state나 변수같은 것들도 초기값으로 변경됩니다. 원래그럼
그래서 실제 서비스였으면 우선 서버로 보내서 DB에 영구저장을 하거나 그랬겠지만
갑자기 서버와 DB 가르치려면 20강 추가해야하니까 프론트엔드에서만 잘 구현해보면 됩니다.
숙제2. 글마다 삭제버튼과 기능만들기
map 반복문안에 버튼부터 만들면 됩니다.
그 다음에 버튼누르면
“div 하나를 삭제해주세요~” 라고 코드짜는건 틀딱자바스크립트 방식이고
“state에서 글을 삭제해주세요~” 라고 코드짜는건 리액트방식입니다.
리액트방식으로 코드짜보면 됩니다.
function App (){
let [글제목, 글제목변경] = useState(['남자코트추천', '강남우동맛집', '파이썬독학']);
let [입력값, 입력값변경] = useState('');
return (
<div>
{
글제목.map(function(a, i){
return (
<div className="list">
<h4>{ 글제목[i] }</h4>
<p>2월 18일 발행</p>
<button onClick={()=>{ ? }}>삭제</button>
</div>
)
})
}
</div>
)
}
▲ 삭제버튼을 글마다 추가해놨는데 이거 누르면 어떤 코드를 실행하면 될까요?
역시 마지막 찬스입니다.
모르는게 나오면 검색해보면 됩니다
array자료에서 x번째 데이터를 삭제하고 싶으면
array자료.splice(x, 1) 이라고 사용하면 된다는군요.
function App (){
let [글제목, 글제목변경] = useState(['남자코트추천', '강남우동맛집', '파이썬독학']);
let [입력값, 입력값변경] = useState('');
return (
<div>
{
글제목.map(function(a, i){
return (
<div className="list">
<h4>{ 글제목[i] }</h4>
<p>2월 18일 발행</p>
<button onClick={()=>{
let copy = [...글제목];
copy.splice(i, 1);
글제목변경(copy);
}}>삭제</button>
</div>
)
})
}
</div>
)
}
일단 버튼누르면 글제목state 사본부터 만들었습니다.
글제목state에서 x번째 데이터를 삭제하고 싶으면 splice(x, 1) 쓰면 된댔습니다.
그래서 저렇게 써봤습니다.
그럼
0번째 삭제버튼 누르면 copy.splice(0, 1) 해주니까 0번글이 없어집니다.
1번째 삭제버튼 누르면 copy.splice(1, 1) 해주니까 1번글이 없어집니다.
2번째 삭제버튼 누르면 copy.splice(2, 1) 해주니까 2번글이 없어집니다.
진짜 그런가 테스트해봅시다.
응용1. 글에 아무것도 입력안하고 발행버튼 누르는거 막으려면?
유저의 의도치않은 행동을 막는 코드도 많이 짜야 안전한 사이트가 됩니다.
응용2. 글을 하나 추가하면 따봉갯수 개별적용하던 것도 이상해질 수 있습니다.
어떻게 해결하면 될까요?
아마 글이 하나 추가되면 따봉기록할 곳도 하나 더 만들어줘야할듯요.
응용3. 날짜데이터는?
state에 글만 저장되어있는데 날짜같은 것도 저장해두고 보여주는 식으로 하면 재밌을 것 같군요.
자바스크립트로 현재 날짜같은 것도 출력해볼 수 있어서 글 발행시 그런 기능을 더해줄 수도 있겠네요.
class를 이용한 옛날 옛적 React 문법
여러분은 현재 최신문법으로 공부하고 계시지만
실무하다보면 옛날문법으로 작성된 리액트파일 볼 때가 있습니다.
그런 것들도 이해는 할 수 있어야겠죠?
컴포넌트 만들기, 함수만들기, state 만들고 변경하기는 예전엔 어떻게 했었는지 알아봅시다.
사이트 내에 프로필 UI를 만들고 싶은데 component로 만들어보겠습니다
옛날 문법으로 component는 이렇게 만들었습니다.
function App(){
return (
<div>
HTML 잔뜩있는 곳
<Profile />
</div>
)
}
class Profile extends React.Component {
constructor(){
super();
}
render(){
return (
<div>프로필영역입니다</div>
)
}
}
이렇게 class부터 시작해서 길게 최소 6줄을 써야합니다.
1 . class를 하나 만들고 이름짓습니다.
2 . 그리고 React.Component라는 이상한 것을 extends한다고 써줍니다.
3 . constructor(){} 함수를 언급해줍니다.
4 . render(){} 함수 안에 원하는 HTML을 적습니다.
그럼 이제 Profile />을 원하는 곳에 첨부하면 Component 만들기 끝입니다.
약간의 문법용어 정리
문법시간이 아니라 짧게 설명하겠습니다.
class는 데이터/함수를 보관하는 덩어리입니다.
extends는 덩어리를 만들 때 오른쪽에 있는 놈 성질을 물려받아서 덩어리를 만들겠다는 소리입니다.
React.Component는 컴포넌트 성질을 갖고있는 덩어리입니다.
이것을 extends 해서 class를 만들면 우리가 계속 사용해왔던 컴포넌트를 만들어낼 수 있습니다.
(리액트 라이브러리 사용법일 뿐입니다)
왜 class라는 문법이 존재하냐면
class는 여러개의 데이터나 함수를 한 곳에 보관하고 싶을 때 쓰는 문법입니다.
class 어쩌구 {} 하시고 중괄호 안에 담고 싶은 데이터나 함수 담으시면 됩니다.
class를 만들어두시면 class가 가지고 있는 데이터를 그대로 복사해서 사용할 수 있는 object를 쉽게 만들 수 있습니다.
혹은 class가 가지고 있는 데이터를 그대로 복사해서 사용할 수 있는 class도 쉽게 만들 수도 있고요. (extends 문법을 씁니다)
암튼 가끔 그러고 싶을 때가 있어서 쓰는 문법인데 리액트는 왜 저러냐면
1 . 리액트 만든 사람들이 컴포넌트와 관련된 데이터/함수들을 보관하기 위해서 React.Component라는 class를 만들어두었고
2 . 그걸 extends 를 이용해서 복사하면 여러분만의 컴포넌트를 만들 수 있는거고
3 . 그리고 그렇게 하시면 여러분 컴포넌트는 리액트관련 데이터/함수를 자유롭게 쓸 수 있는겁니다.
여러분이 리액트 라이브러리 비슷한걸 하나 더 만들게 아니라면 몰라도 먹고사는데엔 지장이 없습니다.
예전 문법으로 state 만들고 쓰는 법
예전엔 constructor(){} 안에 모든 state를 보관했었습니다.
class Profile extends React.Component {
constructor(){
super();
this.state = { name : 'Kim', age : 30 }
}
render(){
return (
<div>
<h3> 저는 { this.state.name } 입니다 </h3>
</div>
)
}
}
1 . state저장할 땐 constructor() 안에 this.state 라는 변수에 전부 보관하셔야합니다.
2 . 그리고 꺼내쓸 때는 this.state.state명 이렇게 쓰시면 됩니다.
약간의 문법용어 정리2
역시 문법시간이 아니라 짧게 설명하겠습니다.
constructor()라는 부분은 변수와 함수가 가득한 class 덩어리를 만들 때.. 새로운 변수를 넣는 공간입니다.
super()는 “extends 했던 React.Component 라는 덩어리에 있던 변수들을 그대로 물려받아 쓰겠습니다~”
라는 뜻이고 꼭 먼저 써주셔야 super() 밑에서 state를 만들 수 있습니다.
state값을 바꾸는 법
버튼을 누를 때 이름을 ‘Park’으로 변경하는 기능을 만들어봅시다.
onClick이라든지 이런건 똑같습니다. 근데 state를 변경하실 때는 특정함수를 쓰셔야합니다.
class Profile extends React.Component {
constructor(){
super();
this.state = { name : 'Kim', age : 30 }
}
render(){
return (
<div>
<h3> 저는 { this.state.name } 입니다 </h3>
<button onClick={ ()=>{ this.setState( {name : 'Park'} ) } }> 버튼 </button>
</div>
)
}
}
1 . 버튼만들고 onClick 이런거 넣는건 똑같습니다.
2 . state를 변경하실 땐 this.setState() 라는 내장함수를 꼭 쓰셔야합니다.
그리고 소괄호()안에는 바꾸고 싶은 state 이름과 값만 적어주시면 됩니다.
주의) 신문법으로 만든 state 변경함수들은 아예 state를 바꿔치기해주는 역할인데
예전문법 setState()는 딱 필요한 부분만 수정해주고 나머지는 건들지 않습니다.
그래서 우리가 했던 것 처럼 1.state 복사본 만들고 2.수정하고 3.복사본을 집어넣고 그런 짓거리가 필요없습니다.
커스텀 함수 만드는 법
최신문법에서 함수는 그냥 아무데나 만들었었는데
예전 문법은 위치가 정해져있습니다.
예를 들어서.. 버튼안에 setState() 복잡하게 하던걸 함수로 빼보도록 하겠습니다.
class Profile extends React.Component {
constructor(){
super();
this.state = { name : 'Kim', age : 30 }
}
changeName(){
this.setState( {name : 'Park'} )
}
render(){
return (
<div>
<h3> 저는 { this.state.name } 입니다 </h3>
<button onClick={ this.changeName }> 버튼 </button>
</div>
)
}
}
1 . 버튼안에 있는 코드가 너무 길어서 함수로 빼고 싶어서 함수를 만들었습니다.
2 . 모든 커스텀 함수는 저기 저 changeName 자리에 만들어주시면 됩니다. 그리고 필요한 코드를 담습니다.
3 . 그리고 changeName 이라는 함수 이름을 필요한 자리에 넣어줬습니다. 근데 this 까먹지맙시다.
맞는 방법인데 에러가납니다.
왜냐면 this.setState()라는 코드의 this가 이상해져서 그렇습니다.
changeName() 만드는 것도 function 문법의 축약버전인데
자바스크립트에선 function을 쓴다면 안에있는 this값은 항상 새롭게 재정의됩니다.
그래서 changeName 안에 있던 this도 재정의가 되어서 의도와는 다른 기능을 하고 있는 것입니다.
그래서 this가 재정의되지않게
그래서 1. 함수를 쓸 때 this.changeName.bind(this) 이렇게 사용하시거나
아니면 2. 함수를 아예 arrow function으로 바꿔주시면 됩니다.
class Profile extends React.Component {
constructor(){
super();
this.state = { name : 'Kim', age : 30 }
}
changeName = () => {
this.setState( {name : 'Park'} )
}
render(){
return (
<div>
<h3> 저는 { this.state.name } 입니다 </h3>
<button onClick={ this.changeName }> 버튼 </button>
</div>
)
}
}
▲ 이런 식으로 하면 에러가 나지 않습니다.
arrow function 과 this 키워드의 관계
자바스크립트에선 () => {} (arrow function) 과 그냥 function(){} 은 거의 같은 의미입니다.
하지만 한가지 차이점이 있는데
arrow function을 쓰시면 안에 있는 this값을 재정의해주지않습니다. 바깥에 있던 this의 값을 그대로 끌고와서 사용합니다.
하지만 function(){}을 쓰시면 this값이 새롭게 변화합니다.
같은 함수문법이지만 이런 차이가 있습니다.
그래서 arrow function은 내부의 this키워드 값을 변화시키지 않고 싶을 때 사용합니다.
문법시간이 아니라 this에 대한 자세한 문법은 스킵했는데
ES6강의 무료파트 들어보시면 this 라는 키워드가 왜 저렇게 맨날 뜻이 달라지는지 알 수 있습니다.
오늘의 교훈 : 신문법을 씁시다.
리액트 공식 문서도 컴포넌트를 만들 땐 function 문법으로 사용하라고 권장합니다.
어려운 class문법이나 this 키워드를 사용하지않아도 되니
세부 문법을 체크할 필요가 없이 매우 빠르고 쉽게 리액트 웹개발이 가능합니다.
function으로 만드나 class로 만드나 기능적 차이는 거의 없습니다.
useState같은 Hook을 자주 사용할 거라면 function이 훨씬 더 유용한 기능이 많습니다.
다만 class 컴포넌트는 Lifecycle Hook을 조금 더 자세히 쓸 수 있습니다.