[TIL][React] 리액트 개괄 feat. 12일차

lezsuuu·2022년 7월 22일
0

TIL

목록 보기
11/42

3주차 시작😤😤😤

리액트(React)란

UI를 구축하기 위한 선언적*이고 효율적이며 유연한 JavaScript 라이브러리.
컴포넌트를 이용하면 데이터에 맞추어 UI를 만들어 주는 기능을 하며, 라이프 사이클 API를 통해 컴포넌트가 화면에 나타날 때, 사라질 때, 변할 때 작업들을 수행할 수도 있다

SPA* (→index 파일이 하나!)를 전제로 하고 있다. JSX*문법을 사용하여 React 요소를 만들고 DOM에 렌더링해서 구현한다. Virtual DOM*을 활용하여 업데이트 해야하는 DOM요소를 찾아서 해당 부분만 업데이트하기 때문에, 리렌더링이 잦은 동적인 모던 웹에서 빠른 퍼포먼스를 낼 수 있다.

컴포넌트(Component)

  • 리액트로 만들어진 앱을 이루는 최소한의 단위
  • MVC*의 뷰를 독립적으로 구성하여 재사용을 할 수 있다
  • 컴포넌트 이름은 항상 대문자로 시작하도록 한다.
    (리액트는 소문자로 시작하는 컴포넌트를 DOM 태그로 취급함)
  • 컴포넌트 종류는 크게 함수형 컴포넌트클래스형 컴포넌트 가 있다

Rendering: HTML 태그를 쓴 것처럼 컴포넌트를 화면에 보여지게 하는 것

🤓 함수형 컴포넌트와 클래스형 컴포넌트

과거에는 클래스형 컴포넌트를 주로 사용하였는데, 2019년부터 함수형 컴포넌트와 훅*을 함께 사용할 것을 권장하고 있다. 클래스형 컴포넌트는 다른 말로 Stateful 컴포넌트, 함수형 컴포넌트는 Stateless 컴포넌트라고 하기도 한다. 클래스형 컴포넌트는 로직과 상태를 컴포넌트 내에서 구현하기 때문에 stateful로 불리는 것이며 상대적으로 복잡한 UI 로직을 가지고 있다. 반면 함수형 컴포넌트는 state를 사용하지 않고 단순하게 데이터를 받아서(props) UI에 뿌려주기 때문에 stateless라고 불리는 것이다.

props

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;

🤓 props Drilling (프로퍼티 내리꽂기)

상위 컴포넌트에서 또 하위 컴포넌트로, 또 하위, 또 하위로.. 컴포넌트가 드릴처럼 밑으로 뚫고 내려가는 것을 의미한다. 상태관리
(State Management) 라이브러리로 동적인 information data를 모아 컴포넌트에 내려주어 Props Drilling 을 효과적으로 해결할 수 있는데 이를 스토어라고 한다.

props.children

자식 컴포넌트에 정보를 전달해주는 다른 방식의 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 기초문법

ES6란 JavaScript의 최신 버전으로 화살표 함수(Arrow function), let, const, ${}, Class 등이 ES6 업데이트로 가능해졌다.

화살표 함수(Arrow function)

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
};

전개 구문(spread operator)

기존에 있는 객체나 배열의 내용을 그대로 가져오거나 새로운 값을 덧붙여서 새로운 객체나 배열을 생성 할 수 있습니다. 기존의 데이터 (객체나 배열)에는 전혀 영향을 주지 않고 복사해서 새로운 것을 만듭니다.(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 operator)

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

props는 object literal 형태이므로 구조 분해 할당을 이용할 수 있다.

function Todo({ title }){
	return <div>{title}</div>
}

defaultProps

부모 컴포넌트에서 props를 보내주지 않아도 설정될 초기 값.

import React from 'react';

function Child({ name }){
	return <div>내 이름은 {name} 입니다. </div>
}

// 이렇게 설정합니다.
Child.defaultProps={
	name: '기본 이름'
}

export default Child

State

컴포넌트 내부에서 바뀔 수 있는 값. 바뀌어야만 하는 정보는 useState로 생성. state를 만드는 은 react에만 존재한다.

const [ value, setValue ] = useState( 초기값(initial state) )
const [name, setName] = useState('이지수')			//예시

Hook

라이프 사이클 메소드를 사용할 수 있게 한다. 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]
    },
  }
})()

useState

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\  			상위 디렉토리로 두 번 이동

실습실습🤸‍♀️

1. App컴포넌트 만들어보기

import React from "react";					//파일 가져오기

function App() {
											// 자바스크립트 작성
  return <div>내가 만든 App컴포넌트!</div>	// JSX 영역

}

export default App;

2. 부모 컴포넌트-자식 컴포넌트

import React from "react";

function Child() {
  return <div>나는 자식입니다.</div>;
}

function Mom() {
  return <Child />
}

function App() {
  return <Mom/>;
}

export default App;  		//'나는 자식입니다.' 출력

3. props

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

4. 반복되는 컴포넌트 처리하기

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;

React - Map

map을 사용해 컴포넌트를 반복 렌더링 할 때는 key를 넣어주어야 한다. 성능의 최적화가 가능하다.
(주의) map((value, index)=>{})와 같이 index를 사용한 key값은 지양해야 한다.


- 선언형: 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링
- SPA: Single Page Application. 서버에서 제공하는 페이지가 한 개
- JSX: JavaScript XML.
- virtual DOM: VDOM. React의 선언적 API를 가능하게 하며, UI를 나타내는 객체로 React elements와 연관
- MVC: 모델-뷰-컨트롤러. 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴
- export: 모듈 내보내기 ↔ import : 모듈 가져오기 - export default : '해당 모듈엔 개체가 하나만 있다’는 사실을 나타낸다. 이때 `{}`없이 모듈을 가져올 수 있다.


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

profile
돌고 돌아 벨로그

0개의 댓글