221128(월)

김민석·2022년 11월 28일
0

Today I Learned

목록 보기
5/30

오전

복습

#리엑트 실행 명령어
cd blog
npm start

Q. React 는 프레임워크일까? 라이브러리일까?
A. 라이브러리

1) 프레임워크 : 원하는 기능 구현에 집중하여 개발할 수 있도록 필요한 기능을 갖추고 있는 것, 일정한 형태를 가지고 다양한 형태의 결과물을 만드는 것

2) 라이브러리 : 소프트웨어를 개발할 때 프로그래밍 사용하는 비휘발성 자원의 모임, 공통으로 사용될 수 있는 특정한 기능들을 모듈화한 것

둘의 차이점은 어플리케이션의 제어 흐름의 권한을 누가 가지고 있느냐가 핵심
https://canoe726.tistory.com/23


리액트 useState hooks

좋아요 예제

/* eslint-disable */
import './App.css';
import { useState, useEffect } from 'react';
//class UserApp extends React.Component{ }

function App() {
  let [title] = useState(['혜화 맛집 튀김' , '송파 샤브샤브','홍대 일식집']) 
  //값이 하나씩 대응된다.
  let [like, setLike] = useState(0);
  //useState("string") 훅은 배열 형태로 2개의 값이 전달된다.
  function fnlike(){
    setLike(like+1);
  }
  return (
<div className="App">
	{title[0]}  <span onClick={ fnlike }>좋아요</span> {like}
</div>
  );
}
export default App;

타이틀 정렬 예제

수업때 대강 넘어감, 찾아서 공부하자

Component

props

교재 92~117p
p90
function()은 return()안의 name을 가리킴 (검둥이)
() => 는 class의 name을 가리킴 (흰둥이)

props값 지정

//App.js
import React from 'react';
import './App.css';
import MyComponent from './MyComponent';
function App() {
return (
  <MyComponents/>
  );
}
export default App;
//MyComponents.js
const MyComponent = () => {
    return <div>나의 새롭고 멋진 컴포넌트</div>
};
export default MyComponent; // 이 파일을 import할 때, MyComponent클래스를 불러오도록 설정한다

결과 : 나의 새롭고 멋진 컴포넌트


//App.js
import React from 'react';
import './App.css';
import MyComponent from './MyComponent';
function App() {
return (
  <MyComponents name="React"/>
  );
}
export default App;```
```js
//MyComponents.js
const MyComponent = (props) => {
    return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>
};
export default MyComponent;

결과 : 안녕하세요, 제 이름은 React입니다.


default 값 지정

!!! 기본값 지정하는 방법은 MyComponents.js에 아래 코드 추가

MyComponent.defaultProps = {
    name : '기본 이름'
}

children

//App.js
import React from 'react';
import './App.css';
import MyComponent from './MyComponent';
function App() {
return (
  <MyComponents name="React">리엑트</MyComponent>
  );
}
export default App;
//MyComponents.js
const MyComponent = (props) => {
    return (
      <div>
      안녕하세요, 제 이름은 {props.name}입니다.
      children 값은 {props.children}입니다.
      </div>
	)
};
export default MyComponent;

결과 : 안녕하세요, 제 이름은 React입니다. children 값은 리엑트입니다


props. 생략해보기 : 비구조화 할당 문법

1번방법

//MyComponents.js
const MyComponent = (props) => {
  const { name, children } = props;
    return (
      <div>
      안녕하세요, 제 이름은 {name}입니다.
      children 값은 {children}입니다.
      </div>
	)
};
export default MyComponent;

2번방법

//MyComponents.js
const MyComponent = ({ name, children }) => {
    return (
      <div>
      안녕하세요, 제 이름은 {name}입니다.
      children 값은 {children}입니다.
      </div>
	)
};
export default MyComponent;

propTypes를 통한 props 검증

먼저 상단에 import시켜줘야 한다.

import PropTypes from 'prop-types';

이후 MyComponents.js파일에 아래 코드 추가

MyComponent.propTypes = {
    name : PropTypes.string
}

결과: name값은 무조건 문자열 형태로 전달됨.

isRequired를 사용한 필수 propTypes 설정

prpTypes를 지정하지 않았을 때 경고 메시지를 띄워주는 작업.

//MyComponents.js
const MyComponent = ({ favoriteNumber }) => {
    return (
      <div>
      제가 좋아하는 숫자는 {favoriteNumber}입니다.
      </div>
	)
};
MyComponent.propTypes = {
    favofiteNumber: PropTypes.number.isRequired
}
export default MyComponent;

결과 : App.js에서 favoriteNumber가 숫자가 제대로 넘어오지 않았기 때문에 경고가 뜬다. App.js에 favoriteNumber={1} 을 추가해주자

클래스형 컴포넌트에서 props 사용

위의 컴포넌트는 다음과 같이 변환할 수 있다. 차이를 주목해보자

//MyComponent.js
import { Component } from "react";
import PropTypes from 'prop-types';
class MyComponent extends Component{
    static defaultProps = {
        name : '기본 이름'
    };
    static propTypes = {
        name : PropTypes.string,
        favoriteNumber : PropTypes.number.isRequired
    };
    render(){
        const {name, favoriteNumber, children} = this.props;
     return(
            <div>
                안녕하세요, 제 이름은 {name}입니다.
                child값은 {children}입니다.
            </div>
     );   
    }
}
export default MyComponent;

import{Component}from 'react';가 추가되었다.
default와 propType가 MyComponent안으로 들어왔다.

state

state는 컴포넌트 내부에서 바뀔 수 있는 값
props는 부모로부터 전달받은 값으로 컴포넌트 내부에서 변경불가능
여기서 state는 두가지 종류가 있는데 하나는 클래스형 컴포넌트의 state, 다른 하나는 useState

//state 예제
import {Component} from 'react';

class Counter extends Component{

    constructor(props){
        super(props)
        // state의 초기값 설정하기
        this.state = {
            number:0
        };
    }

    render(){
        const {number} = this.state; // state를 조회할때는 this.state로 조회
     return(
            <div>
                <h1>{number}</h1>
                <button
                // onclick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
                onClick={()=>{
                    // this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
                    this.setState({number:number+1});
                }},
  				()=>{
                console.log('setState호출');
               	console.log(this.state);
                }
                >+1</button>
            </div>
     );   
    }
}
export default Counter;

결과


생성자 constructor 말고 다른방법으로 지정해주기

//기존
    constructor(props){
        super(props)
        // state의 초기값 설정하기
        this.state = {
            number:0
        };
    }
//New
    state = {
    	number: 0,
      	fixedNumber: 0
    }

useState

//Say.js
import { useState } from 'react';

const Say = () => {
    const[message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕하세요');
    const onClickLeave = () => setMessage('안녕히 가세요!');

    return(
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1>{message}</h1>
        </div>
    );
};
export default Say;

결과 :


!!! 여러개의 컴포넌트를 다룬다면? (성공x)

//App.js
import MyComponent1 from './components/MyComponent1';
import MyComponent2 from './components/MyComponent2';
<MyComponente1/><MyComponente2/>

//component.js
export default {MyComponent1 , MyComponent2 ...};

컴포넌트를 활용한 프론트엔드


• HTML 로 문서 구조 구현하고,
• CSS 로 스타일을 입히고,
• JavaScript 로 DOM 을 조작한다. (기능, 동작)


• 컴포넌트를 정의하고
• 실제 DOM에 컴포넌트를 그려준다.

ReactDom.render(리엑트컴포넌트, document.querySelector('#root'));
React.createElement(
	type, //태그이름 문자열, 리엑트 컴포넌트, React.Fragment
    [props], //리엑트 컴포넌트에 넣어주는 데이터 객체
    [...children]  //자식으로 넣어주는 요소들
)
//1.태그이름문자열 type
ReactDom.render(
  React.createElement('h1',null,`type is "tagNameString" !!!.`),document.querySelector('#root')
);
//2. React Component type
const Component type
Const Component = props => {
  return React.createElement(
  	'p',
    null,
    `type is "tagNameString" !!!.`
  );
};
ReactDom.render( 
  React.createElement(Component,null,null),document.querySelector('#root')
);



오후

Hooks

교재 p194

useEffect

컴포넌트가 렌더링 될 때마다 특정 작업을 수행하게 설정 할 수 있는 훅.
컴포넌트 안에 useEffect(()=>{});를 사용해서 구현하면 된다.
ex) console.log('렌더링이 완료되었습니다!');

// !!!처음 렌더링될때만 실행시키고 싶다면?
useEffect(()=>{console.log('렌더링이 완료되었습니다!');},[]);

// !!!특정 값이 업데이트 될 때만 실행하고싶다면?
useEffect(()=>{console.log(name);},[name]);

가시성관리

//App.js
import { useState } from "react";
import Info from './Info';

const App = () => {
    const [visible, setVisible] = useState(false);
    return (
        <div>
            <button onClick={() => {
                setVisible(!visible);
            }}
            >
                {visible ? '숨기기' : '보이기'}
            </button>
            <hr />
            {visible && <Info />}
        </div>
    );
};

export default App;

useReducer

지금은 어려우니 17장 학습 후 추후 학습


useMemo

값이 변경될 때마다(onChange)계산될 필요가 없고, 입력이 되었을 때만 연산 되게 함으로써 낭비를 줄이게 하는 훅.

//Average.js
import { useState,useMemo } from "react";
{/* useMemo를 사용하겠다. */}
const getAverage = numbers => {
    console.log('평균값 계싼 중..');
    if (numbers.length === 0) return 0;
    const sum = numbers.reduce((a,b) => a+b);
    return sum / numbers.length;
}

const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');

    const onChange = e => {
        setNumber(e.target.value);
    };
    const onInsert = e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    }
	
    const avg = useMemo(()=>getAverage(list),[list]);
  {/*기존의 getAverage(list)대신 추가된 함수 */}
  	return (
        <div>
            <input value={number} onChange={onChange} />
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value,index)=>(
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값 : </b> {avg}                 
			{/* //기존의 코드 : getAverage(list) -> avg */}

            </div>
        </div>
    );
};

export default Average

결과 : 값이 바뀌어도 더이상 계산이 돌아가지 않음.



useCallback

useCallback은 useMemo와 상당히 비슷한 함수.
값이 아닌 만들어 놨던 함수를 재사용한다.
위의 Average함수에서 onChange와 onInsert는 렌더링 될때마다 새로 함수가 생성되고 있는데 이 부분을 최적화 할 수 있다.

//변경,추가되는 부분
import { useState,useMemo,useCallback } from "react";

...

const onChange = useCallback(e => {setNumber(e.target.value);},[]); 
//컴포넌트가 처음 렌더링 될 때만 함수 생성

const onInsert = useCallback( e => {const nextList = list.concat(parseInt(number));
	setList(nextList);
	setNumber('');
    },[number,list]);
//number 혹은 list가 바뀌었을 때만 함수 생성

...

useRef

ref를 쉽게 사용해주는 훅, 사용법만 간단히 보고 가자

//변경,추가되는 부분
import { useState,useMemo,useCallback,useRef } from "react";

...

const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');
	const inputEl = useRef(null);
    
...

const onInsert = useCallback( e => {const nextList = list.concat(parseInt(number));
	setList(nextList);
	setNumber('');
    },[number,list]);
    inputEl.current.focus();
//number 혹은 list가 바뀌었을 때만 함수 생성

...
return(
        <div>
            <input value={number} onChange={onChange} ref={inputEl} />    	

결과 : useRef를 통해 만든 객체 안의 current값이 실제 엘리먼트를 가리킨다.



그외 다른 개발자들이 만든 다양한 Hook 리스트

링크1
링크2

알고리즘 풀이

프로그래머스 lv0

점의 위치 구하기

2차원으로 만들기

공던지기

배열회전시키기

profile
뉴비개발자

1개의 댓글

comment-user-thumbnail
2022년 11월 28일

추가학습필요 :
여러개의 컴포넌트 동시에 app에 넣는방법,
타이틀 정렬 예제

답글 달기