3주차 시작😤😤😤
UI를 구축하기 위한 선언적*이고 효율적이며 유연한 JavaScript 라이브러리.
컴포넌트
를 이용하면 데이터에 맞추어 UI를 만들어 주는 기능을 하며, 라이프 사이클 API를 통해 컴포넌트가 화면에 나타날 때, 사라질 때, 변할 때 작업들을 수행할 수도 있다
SPA* (→index 파일이 하나!)
를 전제로 하고 있다. JSX*문법을 사용하여 React 요소를 만들고 DOM에 렌더링해서 구현한다. Virtual DOM*을 활용하여 업데이트 해야하는 DOM요소를 찾아서 해당 부분만 업데이트하기 때문에, 리렌더링이 잦은 동적인 모던 웹에서 빠른 퍼포먼스를 낼 수 있다.
함수형 컴포넌트
, 클래스형 컴포넌트
가 있다Rendering
: HTML 태그를 쓴 것처럼 컴포넌트를 화면에 보여지게 하는 것
과거에는 클래스형 컴포넌트를 주로 사용하였는데, 2019년부터 함수형 컴포넌트와 훅*을 함께 사용할 것을 권장하고 있다. 클래스형 컴포넌트는 다른 말로 Stateful 컴포넌트, 함수형 컴포넌트는 Stateless 컴포넌트라고 하기도 한다. 클래스형 컴포넌트는 로직과 상태를 컴포넌트 내에서 구현하기 때문에 stateful로 불리는 것이며 상대적으로 복잡한 UI 로직을 가지고 있다. 반면 함수형 컴포넌트는 state를 사용하지 않고
단순하게 데이터를 받아서(props) UI에 뿌려주기 때문에 stateless라고 불리는 것
이다.
props
란 부모 컴포넌트로부터 받아온 데이터를 말한다. object literal 형태이기 때문에 {props.object}
로 꺼내서 사용할 수 있다.
(주의) 자식 컴포넌트에서는 부모 컴포넌트로 props를 전달할 수 없다. 오직 부모 컴포넌트에서 자식 컴포넌트로만 props를 전달
할 수 있다.
import React from "react";
function Child(props){
console.log(props) // 이게 바로 props
return <div>연결 성공</div>
}
function Mother() {
const name = '홍부인';
return <Child motherName={name} />;
}
function App() {
return <Mother />;
}
export default App;
상위 컴포넌트에서 또 하위 컴포넌트로, 또 하위, 또 하위로.. 컴포넌트가 드릴처럼 밑으로 뚫고 내려가는 것을 의미한다. 상태관리
(State Management) 라이브러리로동적인 information data
를 모아 컴포넌트에 내려주어 Props Drilling 을 효과적으로 해결할 수 있는데 이를스토어
라고 한다.
자식 컴포넌트에 정보를 전달해주는 다른 방식의 props
import React from "react";
function User(props) {
console.log(props.children)
return <div></div>;
}
function App() {
return <User>안녕하세요</User>;
}
export default App;
children
은 Layout 컴포넌트를 만들 때 자주 사용한다.
(약간 css파일 import하는 느낌...?)
ES6란 JavaScript의 최신 버전으로 화살표 함수(Arrow function)
, let
, const
, ${}
, Class
등이 ES6 업데이트로 가능해졌다.
function sayHello () { //Function keyword
return "hello world!"
}
const sayHello = () => { //Arrow function
return "hello world!"
}
const sayHello = () => "hello world!" //1줄에서는 return 생략 가능
// 예시 1
<App onClick={ ()=>{} } /> //inline에서 무명함수로 생성
// 예시 2
{array.map((item)=> <div>{item}</div>)}
배열 혹은 객체에서 각각 값(value)이나 프로퍼티(property) 를 분해하여 손쉽게 별도의 변수에 담을 수 있도록 해 줍니다.
const user = {name: "지수", age: 10};
console.log(user.name) // 지수
console.log(user.age) // 10
//__객체 구조분해할당 사용__
const { name, age } = user
console.log(name) // 지수
console.log(age) // 10
const games = ['배틀그라운드', '리그오브레전드'];
console.log(game[0]) // 배틀그라운드
console.log(game[1]) // 리그오브레전드
//__배열 구조분해할당 사용__
const [battleGround, Lol] = games;
console.log(battleGround); // 배틀그라운드
console.log(Lol); // 리그오브레전드
// 객체일 때
const getUserName = ({name, age}) => {
return name;
};
// 배열일 때
const getUserName = ([name, age]) => {
return name
};
기존에 있는 객체나 배열의 내용을 그대로 가져오거나 새로운 값을 덧붙여서 새로운 객체나 배열을 생성
할 수 있습니다. 기존의 데이터 (객체나 배열)에는 전혀 영향을 주지 않고 복사
해서 새로운 것을 만듭니다.(Shallow Copy에 속함)
const box = {size: "big", color: "red"};
const newBox = { ...box}; // {size: "big", color: "red"}
const newBlueBox = {...box, color: "blue" }; // {size: "big", color: "blue"}
rest 문법은 spread와 비슷해보이지만 조금 다른 기능을 합니다. 객체나 배열에서 구조 분해 할당을 했을 때 나머지 정보를 묶어서 표현
할 수 있습니다. rest
라는 키워드를 꼭 사용하지 않아도 되고, 개발자가 편한 키워드를 사용해도 됩니다.
const user ={id: 1, name: "둘리", age: 10, location: "seoul"};
// rest 사용
const {name, ...rest} = user;
// 콘솔에 rest를 찍어보면, 구조분해 할당을 한 정보를 제외한 나머지 값을 보여줍니다.
console.log(rest) // {id: 1, age: 10, location: "seoul"}
props는 object literal 형태이므로 구조 분해 할당을 이용할 수 있다.
function Todo({ title }){
return <div>{title}</div>
}
부모 컴포넌트에서 props를 보내주지 않아도 설정될 초기 값.
import React from 'react';
function Child({ name }){
return <div>내 이름은 {name} 입니다. </div>
}
// 이렇게 설정합니다.
Child.defaultProps={
name: '기본 이름'
}
export default Child
컴포넌트 내부에서 바뀔 수 있는 값. 바뀌어야만 하는 정보는 useState
로 생성. state를 만드는 훅
은 react에만 존재한다.
const [ value, setValue ] = useState( 초기값(initial state) )
const [name, setName] = useState('이지수') //예시
라이프 사이클 메소드를 사용할 수 있게 한다. class의 this.setState
와 유사하지만 이전 state와 새로운 state를 합치지 않는다. class 없이 React를 사용할 수 있게 해준다. useState
, useEffect
등이 있다.
🤓 setState가 const를 변경할 수 있는 이유는?
const MyReact = (function() { let hooks = [] // state 값들이 저장되는 배열 let currentHook = 0 // 새로운 state가 시작될 index return { render(Component) { const Comp = Component() // Counter 객체, useState 생성 Comp.render() // 'render', { count, text } 출력 currentHook = 0 // compnentHook이 render 될 때마다 0으로 초기화 되는 이유는 // 다음 컴포넌트의 render를 위해서 // 인덱스가 0부터 시작하여 useState의 호출 횟수와 같아야 하기 때문이다. // component의 가장 최근 state들은 component의 return 과정에서 // 클로저에 의하여 setCount, setText의 인자 형태로 저장되어있다. // ex) setCount(count + 1) // setState가 실행되면 setStateHookIndex의 위치에 newState 값으로 덮어씌여진다. // hooks 배열에는 가장 최근에 setState 된 값들이 저장되는 것이다. // 이후 componet의 useState가 호출되면서 // hooks[currentHook] 값들에 알맞게 대응되어 새로운 state값을 반환한다. // render를 해줘야 새로운 useState가 호출되고 // 클로저 개념으로 인해 state 값들이 컴포넌트의 onClick 함수의 파라미터로 저장이 된다. // 그렇기 때문에 setState를 호출하면 무조건 !!렌더링!!을 해주어야 값이 섞이지 않는다. // 과정이 끝나게 되면 다음 컴포넌트를 위해 currentHook을 다시 0으로 초기화해준다. return Comp // Counter 객체가 반환됨 }, useState(initialValue) { hooks[currentHook] = hooks[currentHook] || initialValue const setStateHookIndex = currentHook const setState = (newState) => (hooks[setStateHookIndex] = newState) // setState에서 클로저의 개념으로 인해 setStateHookIndex 값은 저장된다. return [hooks[currentHook++], setState] }, } })()
onClick
import React, { useState } from "react";
function App() {
const [name, setName] = useState("Jisu1");
function onClickHandler() {
setName("Jisu2");
}
return (
<div>
{name}
<button onClick={onClickHandler}>버튼</button>
</div>
);
}
export default App;
onChange
import React, { useState } from "react";
const App = () => {
const [value, setValue] = useState("");
const onChangeHandler = (event) => {
const inputValue = event.target.value;
setValue(inputValue);
};
console.log(value)
return (
<div>
<input type="text" onChange={onChangeHandler} value={value} />
</div>
);
};
export default App;
메모리에 있는 값을 변경할 수 없는 것.
원시데이터 | 객체, 배열, 함수 |
---|---|
불변성 있음 | 불변성 없음 |
값이 같다면 같은 메모리 참조 | 값이 같아도 메모리 공간이 다름 |
새로운 값 할당 시 새로운 메모리공간에 저장 | 새로운 값 할당 시 기존 메모리에서 수정 |
=== 에서 true 출력 | === 에서 false 출력 |
React에서는 state의 상태를 확인하기 위해 메모리주소
를 비교한다. 따라서 객체, 배열, 함수를 수정할 때 메모리주소 바꾸지 않으면 리렌더링이 일어나지 않는다
import React, { useState } from "react";
function App() {
const [dogs, setDogs] = useState(["말티즈"]);
function onClickHandler() {
setDogs([...dogs, "시고르자브르종"]);
}
console.log(dogs);
return (
<div>
<button onClick={onClickHandler}>버튼</button>
</div>
);
}
export default App;
배열을 setState
할 때 불변성
을 지켜주기 위해, 직접 수정을 가하지 않고 전개연산자
를 사용해서 기존의 값을 복사하고, 그 이후에 값을 수정하는 식으로 구현한다.
🤓
spread
,map
,concat
,filter
등으로 불변성을 지킬 수 있다.
절대경로
: 웹페이지나 파일이 가지고 있는 고유한 경로
ex) http://www.naver.com, C:\users\document\untitled.jpg 등
상대경로
: 파일이 위치한 곳을 기준으로 하는 경로
ex) index.php가 C:\index\a에 위치
/ == C:\ 가장 최상의 디렉토리
./ == \a 현재 디렉토리
../ == \index\ 파일 있는 곳의 상위 디렉토리
../../ == C\ 상위 디렉토리로 두 번 이동
import React from "react"; //파일 가져오기
function App() {
// 자바스크립트 작성
return <div>내가 만든 App컴포넌트!</div> // JSX 영역
}
export default App;
import React from "react";
function Child() {
return <div>나는 자식입니다.</div>;
}
function Mom() {
return <Child />
}
function App() {
return <Mom/>;
}
export default App; //'나는 자식입니다.' 출력
import React from "react";
function Child(props) {
return <div>{props.dadname}</div>
}
function Mom(props) {
return <Child dadname={props.dadname}/>
}
function Dad() {
const name = '아빠'
return <Mom dadname={name}/>
}
function App() {
return <Dad/>
}
export default App
import React from "react";
function User(props) {
const squareStyle = {
width: "100px",
height: "100px",
border: "1px solid green",
borderRadius: "10px",
display: "flex",
alignItems: "center",
justifyContent: "center",
};
return (
<div style={squareStyle}>
<div>{props.user.age}살 - </div>
<div>{props.user.name}</div>
</div>
);
}
function App() {
const style = {
padding: "100px",
display: "flex",
gap: "12px",
};
const users = [
{ id: 1, age: 30, name: "송중기" },
{ id: 2, age: 24, name: "송강" },
{ id: 3, age: 21, name: "김유정" },
{ id: 4, age: 29, name: "구교환" },
];
return (
<div style={style}>
{users.map((user) => {
if (user.age<25) {
return <User user={user} key={user.id} />;
} else {
return null
}
})}
</div>
);
}
export default App;
map
을 사용해 컴포넌트를 반복 렌더링 할 때는 key
를 넣어주어야 한다. 성능의 최적화가 가능하다.
(주의) map((value, index)=>{})
와 같이 index를 사용한 key값은 지양해야 한다.
https://ko.reactjs.org/
https://ko.reactjs.org/tutorial/tutorial.html
https://velog.io/@quin1392/ES6%EC%9D%98-%ED%8A%B9%EC%A7%95 ES6의 특징
https://blog.logrocket.com/solving-prop-drilling-react-apps/ Props Drilling
https://dudghsx.tistory.com/18 const와 setState