-
[20221125] 항해99 주특기 리액트 첫날🍁(feat. 코딩애플 리액트 강의)TIL 2022. 11. 25. 19:46
오늘부터 코딩 애플의 리액트 강의를 듣기 시작했다. 가장 먼저 JSX 문법 세가지를 배웠다. 첫번째는 태그에 클래스를 설정할 때에는 className으로 해야한다는 것. 두번째로 중괄호를 이용하면 어디든 변수를 중괄호에 넣어 나타낼 수 있다는 것이다. 이것을 데이터 바인딩이라고 한다. 세번째로 태그 내에서 css를 추가할 때 그냥 html과 다르게 JSX에서는 아래와 같이 object형태로 넣어주고 속성도 "-"기호를 쓰면 안된다는 것이다. 또 value에도 반드시 따옴표안에 넣어주어야한다.
import logo from "./logo.svg"; import "./App.css"; function App() { let post = "강남 우동 맛집"; return ( <div className="App"> <div className="black-nav"> <h4 style={{ color: "red", fontSize: "16px" }}>블로그임</h4> </div> {/* 이렇게 변수를 중괄호에 넣어서 나타내는 것을 데이터 바인딩이라고 함 */} <h4>{post}</h4> </div> ); } export default App;
두번째 강의에서는 함수에서 return 다음에 병렬로 2가지 이상의 태그가 오면 안된다는 것을 배웠다. 하나의 태그가 오고 그 안에 구성해야한다. 또 state에 대해 배웠는데 굳이 변수가 아닌 state를 쓰는 이유는 변수는 값이 수정이 되면 바로 html에 수정된 값이 반영이 안되지만 state는 값이 수정되면 stat를 쓰던 html이 자동으로 재렌더링되면서 값이 바뀌게 되기 때문이다. 그러므로 자주변경될 것 같은 html부분은 state로 만들어 놓자! useState 함수를 사용하면 하나의 배열안에 첫번째로 입력된 값과 두번째로 함수가 담긴 배열이 생기고 이것을 아래 추가로 적어놓은 자바스크립트 Destructuring 문법에 따라 할당을 하여 사용하면 된다.
import "./App.css"; import { useState } from "react"; function App() { // 왜 변수가 아닌 state를 써야할까? // 변수는 수정이 되면 바로 html에 수정된 값이 반영이 안되지만 state는 값이 수정되면 stat를 쓰던 html이 자동으로 재렌더링되면서 값이 바뀌게 된다. // 그러므로 자주변경될 것 같은 html부분은 state로 만들어 놓자! // state를 변경할 때는 반드시 state 변경함수를 사용해야하고, 이 함수를 통해 변경해야만 html 재렌더링이 일어난다. // state를 변경하는 법 : state변경함수(새로운 state) let post = "강남 우동 맛집"; let [글제목, 글제목변경] = useState([ "남자 코트 추천", "강남 우동 맛집", "파이썬 독학", ]); // 이렇게 하면 ["여자 코트 추천", 함수] 가 남는다. let [a, c] = [1, 2]; // Destructuring 문법 let [따봉, 따봉변경] = useState(0); // 참고로 return 다음에는 병렬로 2가지 이상의 태그가 오면 안된다. 하나의 태그가 오고 그 안에 구성해야함! return ( <div className="App"> <div className="black-nav"> <h4>React Blog</h4> </div> <div className="list"> <h4> {글제목[0]}{" "} <span onClick={() => {따봉변경(따봉 + 1);}}>👍</span>{따봉} </h4> <p>11월 25일 발행</p> </div> <div className="list"> <h4>{글제목[1]}</h4> <p>11월 25일 발행</p> </div> <div className="list"> <h4>{글제목[2]}</h4> <p>11월 25일 발행</p> </div> <button onClick={() => { let copy = [...글제목]; copy[0] = "여자 코트 추천"; 글제목변경(copy) }}>글수정!</button> // 과제 부분 <button onClick={() => { let copy = [...글제목]; copy.sort() 글제목변경(copy) }}>가나다순 정렬!</button> // 컴포넌트 <Modal></Modal> {/* <Modal/> 이런 식으로 해도 같은 의미다! */} </div> ); } // 이렇게 다른 함수 바깥에서 컨포넌트를 만듦으로써 위의 APP함수에서 깔끔하고 의미를 명확히 알 수 있는 html을 만들 수 있다. // 대문자로 만들어야 한다!! function Modal(){ return ( <div className="modal"> <h4>제목</h4> <p>날짜</p> <p>상세내용</p> </div> ) } export default App;
그리고 위와 같이 state를 변경할 때는 반드시 state 변경함수를 사용해야하고, 이 함수를 통해 변경해야만 html 재렌더링이 일어난다. state를 변경하는 법은 "state변경함수(새로운 state)"와 같이 하면 된다.
마지막 부분에는 "글수정!" 버튼을 누르면 첫번째 글제목인 "남자 코트 추천"이 "여자 코트 추천"으로 바뀌는 기능이 구현되어 있다. 핵심은 원본 데이터를 파괴시키지 않고 복사를 해서 사용해야하는 것이다. 여기서 두가지 중요개념이 등장한다.
"let copy = 글제목"으로 먼저 하게 된다고 가정하자. "copy === 글제목"을 했을때 이것이 원시형이 아니라 배열이다보니 참조형(reference date type)이어서 값 자체를 비교하는 게 아니라 값들이 할당된 RAM의 메모리 주소, 즉 값들을 가리키는 화살표를 비교하게 된다. 그렇기 때문에 "copy[0] = "여자 코트 추천""과 같이 아무리 값을 바꿔도, 가리키는 화살표(주소값)는 똑같기 때문에 copy와 글제목이 같다고 인식하게 된다. 같다고 인식을 하게 되면 글제목변경함수는 동작하지 않는다. 화살표는 여전히 같기 때문이다. 그리고 이것은 저번에 배운 얕은 복사이기 때문에 원본인 글제목의 값이 바뀌어져 있을 것이다. 그러므로 깊은 복사인 shallow copy를 하기 위해선 "let copy = [...글제목]"으로 해주어야 한다. 그래야 copy변수 자체적으로 RAM에 메모리를 할당하고 메모리 주소를 갖게 된다. 결론은 배열이나 객체를 복사하려면 spread 연산자를 사용하여 깊은 복사를 하자!
그런데 사실 이것 또한 얕은 복사이지 엄격한 의미의 깊은 복사가 아니다. 깊은 복사는 json을 활용해야만 한다. 그런데 왜 깊은 복사와 사실상 같은 기능을 하는가? 그건 바로 배열안에 들어있는 것들이 전부 원시값이기 때문이다. 원시값의 경우에는 얕은 복사를 해도, 복사한 배열에 다른 원시값을 할당하면 자연스레 복사한 배열의 해당 위치에 다른 원시값의 주소가 할당되므로 원본과 복사본이 차이가 나게된다. 그런데 원시값이 아니라 객체나 배열이 하나의 요소로 들어있다면 어떻게 되는가? 객체 자체를 복사본에서 원시값으로 바꾸면 원시값은 단절시킬 수 있기 때문에 깊은 복사와 기능이 같아지지만 하나의 요소로서의 객체안의 값들을 변경한다면, 객체는 참조값이기 때문에 복사본과 원본 모두 변경된 객체를 요소로 갖게된다!!!
즉 나름의 결론을 내자면, 배열을 복사할 때 안에 들어있는 요소들이 원시값들인 경우나 객체가 있다고 할지라도 요소들을 무조건 원시값으로만 변경할 것이라면 얕은 복사를 해도 상관없다. 그런데 만약 요소들 중 객체나 배열이 있는데, 그것들의 내용물을 바꾼다면 깊은 복사를 필수적으로 해야할 것이다!
let copy = 글제목; copy[0] = "여자 코트 추천"; console.log(copy === 글제목) // true가 출력되는 것을 볼 수 있다.
위쪽 코드 아래쪽에 Modal이라는 컴포넌트를 만들었다. 컴포넌트는 이렇게 다른 함수 바깥에서 만듦으로써 위의 APP함수에서 깔끔하고 의미를 명확히 알 수 있는 html을 만들 수 있다. 참고로 컴포넌트는 함수 앞글자를 대문자로 만들어야 한다!! 또한 APP에서 처럼 return () 안엔 html 태그들이 평행하게 여러개 들어갈 수 없다. 왜냐면 아까만든 function App(){}도 사실은 컴포넌트여서 같은 문법이 적용된다. 또 컴포넌트 안에 컴포넌트를 만들 수 없기 때문에 function App(){} 내부에서 컴포넌트를 만들면 안된다.
컴포넌트 언제쓰면 좋나? 사이트에 반복해서 출현하는 HTML 덩어리들은 Component로 만들면 좋다. 내용이 매우 자주 변경될 것 같은 HTML 부분을 잘라서 Component로 만들면 좋다고 하고, 다른 페이지를 만들고 싶다면 그 페이지의 HTML 내용을 하나의 Component로 만드는게 좋다고 한다. 또는 다른 팀원과 협업할 때 웹페이지를 Component 단위로 나눠서 작업을 분배하기도 한다고 한다.컴포넌트의 단점은 state를 가져다쓸 때 문제가 생긴다. A함수에 있던 변수는 B함수에서 맘대로 가져다 쓸 수 없기 때문이다. 그러므로 모든 걸 다 컴포넌트로 만들려고 하지 말자!참고로 실수를 방지하기위해 다음과 같이 함수를 만들기도 한다.
const Modal = () => {} Modal = 123; 이런 식의 실수를 줄이기위해 위와 같이 함수를 만들기도 한다.
'TIL' 카테고리의 다른 글
[221130] 리액트 라이프 사이클과 useEffect (0) 2022.11.28 [20221126] 항해99 주특기 리액트 2일차👍(feat. 코딩애플) (1) 2022.11.26 [20221112] 자바스크립트 함수에 대한 고찰 (feat. 항해99 프리온보딩 6일차) (0) 2022.11.12 [20221111] 자바스크립트 혼공스 함수 연습문제 (feat. 항해99 프리온보딩 5일차) (0) 2022.11.11 [20221110] 자바스크립트 혼공스 반복문 연습문제 (항해99 프리온보딩 4일차) (0) 2022.11.10