state는 리액트 컴포넌트의 상태를 의미함.

쉽게 말하자면 리액트 컴포넌트의 변경 가능한 데이터를 state라고 부름. 사전에 정해진건 아니고 리액트 컴포넌트를 개발하는 각 개발자가 직접 정의해서 사용함.

중요한 점은 렌더링이나 데이터 흐름에 사용되는 값만 state에 포함 시켜야한다는 것임.

->state가변경될 경우 컴포넌트가 재렌더링 되기때문에 렌더링과 데이터흐름에 관련없는 값을 포함하면 컴포넌트가 다시 재렌더링되어 성능저하됨.

그냥 state는 자바스크립트의 객체라고 생각하면됨.

class LikeButton extends React.Component {
	constructor(props) {
    	super(props)
        this.state = {
        	liked: false
         };
      }
  }

여기서 this.state부분이 나오는데 이 부분이 바로 현재 컴포넌트의 state를 정의하는 부분임.

위에같이 class컴포넌트의 경우 state를 constructor이라는 생성자에서 정의하고

함수컴포넌트에서는 state를 useState()라는 훅을 사용하여서 정의함.

 

//잘못된 사용법(state를 직접 수정하는것)
this.state = {
	name: 'taeyoung'
 };
 
 //올바른 사용법(setState를 사용하여서 수정)
 this.setState({
 	name: 'taeyoung'
  });

이렇게 state를 직접 수정할순있지만 리액트에서 인식을 못 할 경우를 생각하여서 그냥 직접수정하지말고 setState를 사용하여서 수정해야됨.

 

리액트 컴포넌트도 사람같이 생명주기를 가지고있음.

그니까 리액트 컴포넌트가 생성되는 시점과 사라지는 시점이 정해져있다는 의미임.

출생 -> 인생 -> 사망

 

먼저 컴포넌트가 생성되는 시점인 출생시점이다 이 과정을 마운트라고 부르는데 이때 컴포넌트의 constructor(생성자)가 실행된다.

이 생성자에서는 컴포넌트의 state를 정의하게된다. 또한 컴포넌트가 렌더링되며 이후에 componentDidMount()함수가 호출이된다.

 

그 다음은 출생을 했으니 인생을 살아가겠지?

사람은 인생을 살아가는 동안 신체적, 정신적으로 변화를 겪잖아 그치? 이처럼 리액트 컴포넌트도 생애동안 변화를 겪으면서 여러번 렌더링됨.

이러한 과정을 업데이트되는 과정이라고 할수있음.

업데이트 과정에서는 컴포넌트의 props가 변경되거나 setState()함수 호출에 의해 state가 변경되거나 forceUpdate()라는 강제 업데이트 함수 호출로 인해 컴포넌트가 다시 렌더링됨.

그리고 렌더링 이후에 componentDidUpdate()함수가 호출됨.

 

그리고 마지막으로는 사망과정

사람은 누구나 나이를 먹고 죽잖아 ㅇㅈ?

리액트 컴포넌트 또한 이 과정을 거치게되는데 이 과정을 언마운트라고 부름.

그럼 컴포넌트는 언제 언마운트가 될까? 바로 상위 컴포넌트에서 현재 컴포넌트를 더 이상 화면에 표시하지 않게 될때 언마운트 된다고 볼 수 있음.

이때 언마운트 직전에 componentWillUnmount()함수가 호출됨.

이 생명주기에서 가장 중요한것은 컴포넌트가 계속 존재하는 것이 아니라 시간의 흐름에 따라 생성되고 업데이트되다가 사라진다는 것임.

 

 

프로그래밍에서 훅은 원래 존재하는 어떤 기능에 마치 갈고리를 거는 것처럼 끼어 들어가 같이 수행되는 것을 의미한다.

리액트에서의 훅도 마찬가지로 리액트의 state와 생명주기 기능에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행되도록 만든것. 그리고 이때 실행되는 함수를 훅이라고 부르기로 정함!

 

이런 훅의 이름은 모두!! use로 시작됨!

훅이 수행하는 기능에 따라서 이름을 짓게 되었는데 각 기능을 사용하겠다는 의미로 use를 앞에 붙임.

 

뭐 대표적인 훅으로는 useState를 들수있다. state를 사용하기 위한 훅이고 

코드를 보면서 이해해보자!

import React, {useState} from "react";

function Counter(props) {
	var count = 0;
    
    return (
    	<div>
        	<p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => count++}>
            	클릭
            </button>
         </div>
     );
}

이건 Counter이라는 함수 컴포넌트이다 딱 보면 버튼 클릭하면 카운트 하나씩 증가시키고 현재 카운트 횟수를 보여주는 간단한 컴포넌트이다.

근데 만약에 이렇게 위해 코딩한거마냥해버리면 버튼 클릭하면 카운트 값이 증가는 되겠지만 재렌더링이 되지않기에 화면에 새로운 카운트 값이 표시가되지않는다. 따라서 이런 경우에는 state를 사용하여서 값이 바뀔때마다 재렌더링을 시켜주어야한다.

 

근데 class컴포넌트가 아닌 함수컴포넌트에는 이런 해당 기능이 따로 없기에 useState를 사용하여서 state를 선언하고 업데이트를 해야한다!

const[변수명, set함수명] = useState(초깃값);

useState()는 다음과 같이 사용이된다!

 

useState()를 호출할때에는 파라미터로 선언할 state의 초깃값이 들어간다.이렇게 초깃값을 넣어 useState()를 호출하면 리턴값으로 배열이 나온다 리턴된 배열에는 두가지 항목이있는데 첫 항목은 state로 선언된 변수이고 두번째 항목은 state의 set함수임.

import React, {useState} from "react";

function Counter(props) {
	const[count, setCount] = useState(0);
    
    return (
    	<div>
        	<p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
            	클릭
             </button>
         </div>
      );
 }

이렇게 useState()를 사용하여 count값을 state로 관리하는건데 이 코드에서 state의 변수명과 함수가 각각 count, setCount로 되어있는것을 볼 수 있지?

버튼 누르면 setCount()함수 호출해서 카운트 1증가시킴 그리고 count값 변경되면 컴포넌트 재렌더링되면서 새로운 카운트값 표시됨.

 

또 많이 쓰이는 훅은 useEffect()!

이 이팩트라는것은 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업을 말함 왜 이걸 이팩트라고 불러? 이 작업들이 다른 컴포넌트에 영향을 미칠수있고, 렌더링중에는 작업이 완료될수없기때문임!

 

이 useEffect는 클래스 컴포넌트에서 제공하는 생명주기 함수인 componentDidMount(), componentDidUpdate(), componentWillUnmount()와 동일한 기능을 하나로 통합해서 제공함 그래서 useEffect()훅만으로 생명주기 함수와 동일한 기능 수행 가능

useEffect(이팩트 함수, 의존성 배열);

첫번째 파라미터로는 이팩트 함수가 들어가고 두번째 파라미터로는 의존성 배열이 들어갑니다.

의존성 배열이란 말 그대로 이 이펙트가 의존하고있는 배열인데 배열안에 있는 변수중에 하나라도 값이 변경되었을때

이펙트 함수가 실행됩니다.

import React, {useState, useEffect} from "react";

function Counter(props) {
	const[count, setCount] = useState(0);
    
    useEffect(() => {
    //브라우저 API를 사용하여 document의 title을 업데이트
    	document.title = `총 ${count}번 클릭했습니다.`;
      });
      
      return (
    	<div>
        	<p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
            	클릭
             </button>
         </div>
      );
 }

아까 사용했던 useState훅에 추가로 useEffect()훅을 사용한것이다. useEffect()함수를 사용하여 생명주기 함수의 기능을 동일하게 수행하도록 만든것인데 useEffect()안에 있는 이펙트 함수에서는 브라우저에서 제공하는 API를 사용해서 document의 title을 업데이트한다. 이 title은 크롬 브라우저에 나오는 탭의 제목이담.

 

위에처럼 useEffect를 의존성 배열없이 사용한다면 처음 컴포넌트가 마운트 되었을때 실행되고, 이후 컴포넌트가 업데이트 될때마다 실행된다.

또한 이 이펙트 함수는 컴포넌트 안에서 선언되자나 맞지? 그래서 props와 state에도 접근가능

보면 count라는 state에 접근할수있잖아.

 

그렇다면 componentWillUnmount()와 동일한 기능은 useEffect로 어떻게 구현이가능할까?

import React, {useState, useEffect} from "react";

function UserStatus(props) {
	const [isOnline, setIsOnline] = useState(null);
    
    function handleStatusChange(status) {
    	setIsOnline(status.isOnline)
      }
      
      useEffect(() => {
      	ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
        return () => {
        	ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
         };
      });
      
      if(isOnline === null) {
      	return '대기중...';
      }
      
      return isOnline ? '온라인' : '오프라인';
   }

 

음 이 useEffect라는게 나도 아직 이해가 잘 안되는부분이라 다시정리할거임 그렇게 알아 ㅎㅎ

이걸 사용함으로써 생명주기 메소드를 함수형 컴포넌트에서도 사용할수있다는거잖아

useEffect()!!!!!!!!!!!!!!!!!!!!!!!

리액트 컴포넌트가 렌더링 될때마다 특정 작업(사이드 이펙트)을 실행할 수 있도록 하는 리액트 훅!!!!

여기서 사이트 이펙트란 컴포넌트가 렌더링 된 이후에 비동기로 처리되어야하는 부수적인 효과들을 뜻함.

자자 기본형태부터 아까 한거부터 다시보자

useEffect(function, deps)

자 여기서 function은 실행하고자하는 함수일거고,

deps는 배열형태이자 function을 실행시킬 조건이야

deps에 특정값을 넣으면 컴포넌트가 mount될때 지정한 값이 업데이트가 될때! -> useEffect를 실행하는거야

자 그러면 이때 deps부분을 생략한다면 어떻게될까? -> 그럼 해당 컴포넌트가 렌더링 될때마다 useEffect가 실행되게돼.

useEffect(() => {
	console.log("렌더링 될때마다 실행");
  });

만약에 맨 처음 렌더링될때 한번만 실행하고 싶으면 deps위치에 빈 배열을 넣어주면돼!!

useEffect(() => {
	console.log("맨 처음 렌더링 될때 한번만 실행")
 },[]);

 

만약에 특정 값이 업데이트 될때만 실행하고 싶을땐 deps위치의 배열안에 실행 조건을 넣어주면됨!

useEffect(() => {
	console.log(name);
    console.log("name값이 업데이트 될때만 실행");
 },[name]);

 

근데 이렇게하면 업데이트될때뿐만 아니라 마운트 될때도 실행되므로 만약에 업데이트될때만 실행시키고싶으면 아래처럼 하면돼!

const mounted = useRef(false);
useEeefct(() => {
	if(!mounted.current) {
    	mounted.current = true;
        } else {
        	console.log(name);
            console.log("업데이트 될때마다 실행");
          }
        },[name]);

 

자 그러면 어떤 예시로 쓰이는지 한번 봐보자고!

import React, {useEffect, useState} from "react";

function UseEffect() {
	const [name,setName] = useState("초기 닉네임");
    
    useEffect(() => {
    	console.log("컴포넌트 나타남");
        console.log(name);
        return () => {
        	console.log("clean up함수");
          };
        });
        
        const onClick = () => {
        	setName("닉네임 변경");
          };
          return (
          	<div>
            	{name} <button onClick={onClick}>변경</button>
            </div>
         );
      }
      
      export default UseEffect;

 

 

useMemo는 Memoized value를 리턴하는 훅임.

파라미터로 create함수와 의존성 배열을 받는다.

의존성 배열에  들어있는 변수가 변했을 경우에만 새로 create함수를 호출하여 결괏값을 반환하며, 그렇지 않은 경우에는 기존 함수의 결괏값을 그대로 반환함.

이걸 사용하면 컴포넌트가 다시 렌더링 될때마다 연산량이 높은 작업을 반복하는 것을 피할수있음.

-> 결과적으로 빠른 렌더링 속도를 얻을 수 있음.

const memoizedValue = useMemo(
	() => {
        //연산량이 높은 작업을 수행하여 결과를 반환
    	return computeExpensiveValue(의존성 변수1, 의존성 변수2);
      },
      [의존성 변수1, 의존성 변수2]
  );

 

useCallback() 훅은 useMemo와 유사한 역할을 함

근데 이 두가지의 차이점은 값이  아닌 함수를 반환한다는점.

마찬가지로 함수와 의존성 배열을 파라미터로 받음!

useCallback()훅에서는 파라미터로 받는 함수를 콜백이라고 부름.

그리고 의존성 배열에있는 변수 중 하나라도 변경되면 메모이제이션된 콜백함수를 반환함.

 

const memoziedCallback = useCallback(
	() => {
    	doSomething(의존성 변수1, 의존성 변수2);
     },
     [의존성 변수1, 의존성 변수2]
 );

만약 이 훅을 사용하지않고 컴포넌트 내에 함수를 정의한다면 매번 렌더링이 일어날때마다 함수가 새로 정의됨.

따라서 useCallback()을 사용하여 특정 변수의 값이 변한 경우에만 함수를 다시 정의하도록하여 불필요한 반복작업을 없애주는것임.

 

useRef()훅은 래퍼런스를 사용하기 위한 훅

여기서 래퍼런스란? 특정 컴포넌트에 접근 할 수 있는 객체를 말함!

 

'REACT' 카테고리의 다른 글

Composition  (0) 2023.07.14
key & form  (0) 2023.07.14
Shared state  (0) 2023.07.13
React Foundation  (0) 2023.06.27
REACT  (0) 2023.04.29

말 그대로 공유된 state를 의미함.

어떤 컴포넌트의 state에 있는 데이터를 여러개의 하위 컴포넌트에서 공통적으로 사용하는 경우를 말함.

어떤 값이 있는 컴포넌트가 있으면 그것에 대하여 그 값에 2를 곱해서 표시하는 컴포넌트와 값이 3을 곱해서 표시하는 컴포넌트 이렇게 두가지 경우가 되는 것처럼..

또 다른 예시를 들어보자면 온도를 받으면 그 온도값에 대해서 온도를 섭씨로 표현하는 컴포넌트와 온도를 화씨로 표현하는 컴포넌트 정도..?

이렇게 지금까지 살펴본것처럼 하위 컴포넌트가 공통된 부모 컴포넌트의 state를 공유하여 사용하는 것을 shared state라고 함.

 

그럼 이제 하위 컴포넌트에서 state 공유하는 것에 대해서 말해보자

아까 예시를 든 온도를 받아서 화씨와 섭씨로 표현해주는 컴포넌트를 만들어보겠음!

우선 섭씨 온도 값을 prop으로 받아서 물이 끓는지 안끓는지를 문자열로 출력해주는 컴포넌트를 만들어보면

function BoilVerdict(props) {
	if (props.celsius >= 100) {
    	return <p>물이 끓습니다.</p>;
        }
      return <p>물이 끓지 않습니다.</p>;
  }

그럼 이제 이 만든 컴포넌트를 실제로 사용하는 부모 컴포넌트를 만들어보자

function Calculator(props) {
	const [temperature, setTemperature] = useState('');
    
    const handleChange = (event) => {
    	setTemperature(event.target.value);
     }
   
   	return (
    	<fieldset>
        	<legend>섭씨 온도를 입력하세요:</legend>
            <input
            	value={temperature}
                onChange={handleChange} />
            <BoilingVerdict
            	celsius={parseFloat(temperature)} />
          </fieldset>
       )
  }

이렇게 아까 만든 컴포넌트에 온도를 입력받고 prop으로 온도를 전달해줘서 온도에 따라서 물이 끓는지 안끓는지를 출력하는 것을 짜보았다.

 

그럼 리액트에서의 장점인 재사용성을 올리기위해서 온도를 입력받는 부분도 따로 컴포넌트로 빼와서 만들어줘보겠음.

 

const scaleNames = {
	c: '섭씨',
    f: '화씨',
 };
 
function TemperatureInput(props) {
	const [temperature, setTemperature] = useState('');
    
    const handleChange = (event) => {
    	setTemperature(event.target.value);
     }
    	
    return (
    	<fieldset>
        	<legend>온도를 입력해주세요(단위:{scaleNames[props.scale]}):</legend>
            <input value={temperature} onChange={handleChange} />
         </fieldset>
      )
  }

이렇게 온도를 입력받는 부분을 추출하였는데 추가적으로 props에 단위를 나타내는 scale을 추가하여 온도의 단위를 섭씨나 화씨로 입력 가능하도록 하였다.

 

그럼 이제 섭씨온도와 화씨온도를 동기화 시키기 위하여 각각 변환하는 두 함수를 만들어주자

function toCelsius(fahrenheit) {
	return (fahrenheit - 32) * 5 /9;
 }

function toFahrenheit(celsius) {
	return (celsius * 9 /5) +32;
 }

이렇게 만든 함수를 호출하는 함수를 만들어보자

function tryConvert(temperature, convert) {
	const input = parseFloat(temperature);
    if(Number.inNaN(input)) {
    	return '';
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000;
    return rounded.toString();
}

이 함수는 첫번째 파라미터로 온도값을 받고 두번째 파라미터로 변환하는 함수를 받아서 변화된 값을 리턴 시켜주는 함수임!

 

tryConvert('abc', toCelsius)
//이렇게 문자열이 들어가면 empty string 출력
tryConvert('10.22', toFahrenheit)
//이러면 변화된 값인 50.396리턴

다음은 이러한 하위 컴포넌트의 state를 공통된 부모 컴포넌트로 올려서 shared state를 적용해야 함.

여기서 state를 상위 컴포넌트로 올린다는것은? state끌어올리기라고 표현함.

그러면 TemperatureInput 컴포넌트에서 온도 값을 가져오는 부분을 아래와  같이 수정해야함.

return (
	//전 코드: <input value={temperature} onChange={handleChange} />
	<input value={props.temperature} onChange={handleChange} />
    ...
    )

이렇게 하면 온도값을 컴포넌트의 state에서 가져오는 것이 아니라 props를 통해서 가져오게됨 

또 컴포넌트의 state를 사용하지 않게되기때문에 입력값이 변경되었을때 상위 컴포넌트로 그 변경된 값을 전달해주어야하기때문에 handleChange()함수를

const handleChange = (event) => {
	//변경전: setTemperature(event.target.value);
    props.onTemperatureChange(event.target.value);
    }

이렇게 사용자가 온도 값을 변경할때마다 props에 있는 onTemperatureChange()함수를 통해 변경된 온도 값이 상위 컴포넌트로 전달되게끔 해줘야함

 

최종 완성본

function TemperatureInput(props) {
	const handleChange = (event) => {
    	props.onTemperatureChange(event.target.value);
     }
    
   return (
   	<fieldset>
    	<legend>온도를 입력해주세요(단위:{scaleNames[props.scale]}): </legend>
        
        <input value={props.temperature} onChange={handleChange} />
     </fieldset>
  )
}

마지막으로 변경된 TemperatureInput 컴포넌트에 맞춰서 Calculator 컴포넌트를 변경해주어야함

function Calculator(props) {
	const [temperature, setTemperature] = useState('');
    const [scale, setScale] = useState('c');
    
    const handleCelsiusChange = (temperature) => {
    	setTemperature(temperature);
        setScale('c');
     }
    
    const handleFahrenheitChange = (temperature) => {
    	setTemperature(temperature);
        setScale('f');
     }
    
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    
    return (
    	<div>
        	<Temperature
            	scale = "c"
                temperature={celsius}
                onTemperatureChange={handleCelsiusChange} />
           
           <Temperature
            	scale = "f"
                temperature={fahrenheit}
                onTemperatureChange={handleFahrenheitChange} />
           
           <BoilingVerdict
           	celsius={parseFloat(celsius)} />
            
         </div>
      );
   }

 

자 그럼 이걸 실제로 만들어볼거임!

 

이런식으로 온도를 입력받는 컴포넌트를 만들어주고

 

이렇게 온도를 바꿔서 출력해주는 컴포넌트를 만듬!

 

결과물!

끝!!

'REACT' 카테고리의 다른 글

key & form  (0) 2023.07.14
Life cycle and hook  (0) 2023.07.14
React Foundation  (0) 2023.06.27
REACT  (0) 2023.04.29
React  (0) 2022.11.09

실제로 각 페이지별로 html 파일이 따로 존재하며 페이지를 이동하게 될 경우 브라우저에서는 해당 페이지의 html파일을 받아와서 화면에 표시해준다!!

근데 페이지가 수많아지면 어떻게 관리를 해야하지?

이런 문제를 해결하기 위하여 나온 것이 바로 SPA(single page application)임.

이건 말그대로 하나의 페이지만 존재하는 웹 또는 어플리케이션임. 페이지가 여러개면 MPA 하나면 SPA (처음에는 이 HTML파일의 바디태그 내부가 텅 비어있다가 해당 페이지에 접속할때 그 페이지에 해당하는 콘텐츠를 가져와서 동적으로 BODY태그 내부를 채워넣게됨.

 

자바스트립트의 함수

함수는 입력을 받아서 정해진 출력을 하는 것

여기서 함수의 입력을 파라미터 또는 인자라고함

자바스크립에서 함수를 정의하는 방법은 두가지인데 첫번째는 FUNCTION SATEMENT이고 두번째는 ARROW FUNCTION EXPRESSION을 사용하는 방법임.

 

FUNCTION STATEMENT를 사용하였을때

function sum(a,b) {
	return a+b;
}

 

ARROW FUNCTION EXPRESSION을 사용하였을때

const multiply = (a,b) => {
	return a*b;
}

 

리액트는 자바스크립트 라이브러리임 라이브러리는 자주 사용되는 기능을 정리해 모아 놓은 것

그럼 사용자 인터페이스를 만들기 위한다는것은 무슨 의미일까 

사용자 인터페이스는 UI라고 하는데 이건 사용자와 컴퓨터 프로그램이 서로 상호작용을 하기 위해 중간에서 서로간에 입력과 출력을 제어해주는 것이 바로 UI임.

걍 우리가 보는 버튼이나 텍스트 입력창같은거임. 히히

리액트는 대표적인 자바스크립트 UI 라이브러리임.

 

뭐 정리하자면 리액트는 사용자와 웹사이트의 상호작용을 돕는 인터페이스를 만들기 위한 자바스크립트 기능 모음집 정도!

 

리액트는 빠른 업데이트를 위해 내부적으로 Virtual DOM이라는 것을 사용함.

쉽게 설명해보자면 Virtual DOM은 말 그대로 가상의 DOM임. DOM은 DOCUMENT OBJECT MODEL의 약자로 웹페이지를 정의하는 하나의 객체라고 생각하면됨. 

쉽게말해서 하나의 웹사이트에 대한 정보를 모두 담고 있는 큰 그릇이라고 보면됨.

 

기존의 방식으로 화면을 업데이트 하려면 DOM을 직접 수정해야하는데 이것은 성능에 영향을 크게 미치고 비용도 굉장히 많이듬. (수정할 부분을 DOM의 데이터에서 모두 찾아야 하기 때문)

하지만 리액트는 DOM을 직접 수정하는 것이 아니라 업데이트해야할 최소한의 부분을 검색하고 검색된 부분만을 업데이트하고 다시 렌더링하면서 변경된 내용을 빠르게 사용자들에게 보여줌.

 

컴포넌트는 구성요소라는 뜻. 리액트는 모든 페이지가 컴포넌트로 구성되어있고, 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성될 수 있음. 따라서 리액트로 개발을 하다보면 레고블록을 조립하는 것처럼 컴포넌트를 조합해서 웹사이트를 개발하게됨. 

 

재사용성! 객체지향프로그래밍에서 등장하는데 소프트웨어 개발에 있어서 매우 중요함. 이건 다시 사용이 가능한 성질인데 이 재사용성은 의존성 문제말고도 여러가지 호환성 문제도 발생할수있음 따라서 재사용성이 높게 개발하는것이 좋음

다시 말하자면 다른 모듈에 의존성을 낮추고 호환성 문제가 발생하지 않도록 개발해야한다!!

 

이러한 재사용성이 높아지면 개발 기간이 단축됨. 기존에 개발해둔 모듈을 곧바로 재사용하여 개발하면 되기때문에 개발기간을 많이 줄일수있음. 

또한 유지보수가 용이함. 소프트웨어에서 공통으로 사용하는 모듈에 문제가 생기면 해당 모듈만 수정해서 다시 배포하면되기때문!

이렇게 재사용성이 높게 개발을 하면 버그를 찾기에도 훨씬 수월함. 재사용성이 높다? -> 모듈간의 의존성이 낮다

따라서 리액트 컴포넌트를 개발할때 항상 쉽고 재사용 가능한 형태로 개발하는 것이 중요함.

 

근데 리액트는 높은 상태 관리 복잡도를 가지고있음. state라는 개념이 있는데 쉽게말해 리액트 컴포넌트의 상태를 의미함. virtual dom은 바뀐 부분만을 찾아서 업데이트한다고 했는데 바뀐 부분이라는 것은 state가 바뀐 컴포넌트를 의미함. 따라서 state는 리액트에서 중요한 부분임.

성능 최적화를 위해 state를 잘관리하는 것이 중요함. 

따라서 상태관리를 할땐 redux등의 외부 상태관리 라이브러리를 사용하는 경우가 많음. ㅈㄴ어렵다는 소리 ㅠㅠ

 

 

jsx는 자바스크립트 확장 문법임. jsx언어는 자바스크립트와 연관이 있으며, 자바스크립트의 문법을 확장시킨것.

jsx = 자바스크립트 + XML/HTML임.

대충 보자면

const element = <h1>Hello world</h1>;

이렇게 자바스크립트와 html코드가 결합되어있음.

이 위에 코드가 하는 역할은 element라는 변수에 h1태그로 둘러싸인 문자열을 저장하는것.

 

jsx는 내부적으로 html코드를 자바스크립트로 변환하는 과정을 거치게됨. 그래서 jsx코드를 작성해서 최종적으로는 자바스크립트 코드가 나오게 되는것.

이때 jsx코드를 자바스크립트 코드로 변환하는 역할을 하는 것이 바로 리액트의 createElement()라는 함수.

 

대충 예시를 들어보자면 

class Hello extend React.Component {
	render() {
    	return <div>Hello {this.props.toWhat}</div>
       }
 }
 
 ReactDOM.render(
 	<Hello toWhat="World" />
    document.getElementById('root')
 );

이건 Hello 라는 리액트 컴포넌트인데 jsx를 사용하고 있는걸 볼 수 있다.

그리고 ReactDOM의 render을 사용하여서 실제 화면에 렌더링하고있다.

 

class Hello extends React.Component {
	render() {
    	return React.createElement('div' , null, `Hello ${this.props.toWhat}`);
     }
}

ReactDOM.render(
	React.createElement(Hello, { toWhat: 'World' }, null),
    document.getElementById('root')
);

이 코드는 jsx를 사용하지않은 순수한 자바스크립트로만 작성된 코드이다 하지만 위코드와 아까 코드는 동일한 역할을 수행함.

jsx를 사용했던 부분이 React.createElement()라는 함수로 대체된걸 볼 수 있음!

---> jsx문법을 사용하면 리액트에서는 내부적으로 createElement()라는 함수로 사용하도록 변환됨.

 

그렇다면!! createElement()함수의 파라미터로는 어떤것이 들어가는지 자세히 살펴보자!!

React.createElement(
	type,
    [props],
    [...children]
)

왜 줄이 안맞지...흠...암튼

첫번째 파라미터로는 엘리먼트의 유형을 나타냄(type) 이 유형으로는 div나 span같은것들, 다른 리액트 컴포넌트같은 것들 있잖아 그런것들이 올 수 있음.

두번째 파라미터로는 props가 들어가게됨. 

세번째로는 children이 들어가게되는데 이 children이란 현재 엘리먼트가 포함하고 있는 자식 엘리먼트.

props란 개념은 추후에 다룰것임! 겁나게 어렵기 때문!

 

이렇게 jsx를 사용하면 createElement를 사용했을때보다 좀 더 간결하고 가독성이 올라가기에 jsx를 사용하는 것을 추천.

그리고 jsx를 사용하면 injection Attack이라 불리는 해킹을 방어할 수 있어서 보안성이 올라감.

const title = response.potentiallyMaliciousInput
const element = <h1>{title}</h1>
//이 코드는 안전함

이렇게 title이라는 변수에 잠재적으로 보안 위험의 가능성이 있는 코드가 삽입되었지만 jsx코드에서는 괄호를 사용하여 title변수를 삽입하고있음.

-> ReactDOM은 렌더링 하기 전에 임베딩(삽입)된 값을 모두 문자열로 변환하여서 명시적으로 선언되지 않은 값은 괄호 사이에 들어갈수없음( 만약 입력창에 문자나 숫자같은 일반적인 입력값이 아닌 소스코드를 입력하여서 해당 코드가 실행이되어버리면 해킹이 될수 있으나 이러한 특징이있어 방어가능)

결과적으로XSS라 불리는 cross-site-scripting attacks방어가능

그냥 좀 뭔가 심심하기도하고 그래서 딴소리좀 했움 ㅎㅎ...

 

jsx를 사용할땐 그냥 html과 자바스크립트가 섞인 형태로 코드를 작성해주면됨.

function formatName(user) {
	return user.firstName + ' ' + user.lastName;
 }
 
 const user = {
 	firstName: 'taeyoung',
    lastName: 'kim'
};

const element = (
	<h1>Hello, {formatName(user)}</h1>
);

ReactDOM.render(
	element,
    document.getElementById('root')
);

이렇게 html 코드 사이에 괄호를 사용해서 변수가 아닌 formatName(user)라는 자바스크립트 함수를 호출.

 

만약 사용자의 이름에 따른 인사말을 표현하고 싶다면?

function greeting(user) {
	if (user) {
    	return <h1> Hello, {formatName(user)}!</h1>
     }
     return <h1>Hi stranger</h1>
}

 

그럼 children을 정의하고싶다면?

그냥 하위태그를 상위태그로 감싼다고 생각하면됨.

const element = (
	<div>
      <h1>안녕</h1>
      <h2>리액트 공부하쟈</h2>
    </div>
 );

이렇게 하면 div태그의 children은 h1과 h2가 됨.

 

 

엘리먼트는 리액트 앱을 구성하는 요소를 의미함. 리액트 공식 홈페이지에서는 엘리먼트는 리액트 앱의 가장 작은 빌딩 블록들이라고 정의하고있음.

엘리먼트는 원래 웹사이트에 대한 모든 정보를 담고있는 객체인 DOM에서 사용하는 용어임.

하지만 DOM엘리먼트와는 다르게 리액트 엘리먼트가 따로있음.

DOM엘리먼트는 웹에서 개발자도구 켜서 나오는것들.

실제 브라우저의 DOM에 존재하는 엘리먼트는 DOM엘리먼트가 되는 것이고 리액트의 Virtual DOM에 존재하는 엘리먼트가 리액트 엘리먼트가 되는것임

즉, 리액트 엘리먼트는 DOM 엘리먼트의 가상 표현

엘리먼트는 컴포넌트 유형 과 속성 및 내부의 모든 자식에 대한 정보를 포함하고있는 일반적인 자바스크립트 객체.

 

이러한 엘리먼트는 불변성이라는 특징을 가지고있는데 엘리먼트는 한번 생성이되면 바꿀수 없기때문에 엘리먼트를 업데이트 하기 위해서는 다시 생성해야한다.

function tick() {
	const element = (
    	<div>
        	<h1>안녕 리액트!</h1>
            <h2> 현재 시간: {new Date().toLocaleTimeString()}</h2>
         </div>
     );
     
     ReactDOM.render(element, document.getElementById('root'));
    
 }
 setInterval(tick, 1000);

이 tick이라는 함수를 정의하고있는 코드는 현재 시간을 포함하고 있는 엘리먼트를 생성하여 root div에 렌더링하는 역할을 함. 

또한 자바스크립트의 setInterval()함수를 사용하여서 tick()함수를 1초에 한번씩 호출하고있음. 

이 코드의 실행결과는 매초 화면에 새로운 시간이 나오는데 이것은 tick함수가 호출될때마다 기존 엘리먼트를 변경하는것이 아니라, 새로운 엘리먼트를 생성하여 바꿔치기 하는것임.

 

근데 여기서 실제로 현재 시간을 초단위로 띄우는 걸 웹으로 표현할때 

 

이렇게 toLocaleTimeString()함수를 사용하여서 실제 시간을 받아온후에 그냥 index.js에 컴포넌트를 가져와서 화면에 나타내기만 하면 되는게 아니라 index에서도 추가작업이 필요함.

초당 새로 업데이트 되는 걸 표현해주기 위하여 

이렇게 setInterval함수를 사용하여서 매초마다 주기적으로 업데이트가 진행이 될수있도록 해주어야함.

 

리액트는 컴포넌트 기반의 구조임!

모든 페이지가 컴포넌트로 구성되어있고 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성

이렇게 컴포넌트를 반복적으로 사용함으로써 전체 코드의 양이 줄어 자연스레 개발시간과 유지보수 비용도 줄일수있음.

 

이러한 리액트 컴포넌트에서의 입력은 props라는 것이고 출력은 앞에서 배운 리액트 엘리먼트가됨

결국 리액트 컴포넌트가 해주는 역할은 어떠한 속성들을 입력으로 받아서 그에 맞는 리액트 엘리먼트를 생성하여 리턴해주는것.

쉽게 말하자면 리액트 컴포넌트는 만들고자하는대로 props(속성)을 넣으면 해당 속성에 맞춰 화면에 나타날 엘리먼트를 만들어주는 것.

더 쉽게말하자면 붕어빵 틀 같은것임 여기서 붕어빵 틀은 컴포넌트, 각 붕어빵들은 엘리먼트

객체지향의 개념에서 나오는 클래스와 인스턴스의 개념과 비슷.

 

props는 리액트 컴포넌트의 속성임. 붕어빵을 만들때 컴포넌트라는 붕어빵 틀에 어떤 props를 넣는지에 따라 각기 다른 엘리먼트들이 나오는것임.

이처럼 props는 리액트 컴포넌트에서 눈에보이는 글자나 색 등의 속성을 바꾸고 싶을때 사용하는 컴포넌트속의 재료.

props는 컴포넌트에 전달할 다양한 정보를 담고 있는 자바스크립트 객체

이러한 props를 통하여 컴포넌트를 통해 엘리먼트를 생성하면 이 생성된 엘리먼트에 대해서는 더이상 props값을 변경할수가없음. 따라서 다른 props값을 넣어주고싶다면 다시 컴포넌트에 값을 넣어서 새로운 엘리먼트를 만들어주면댐.

 

우리가 함수를 구분지을때에는 pure함수와 impure함수로 구분을 하는데 이때 

pure함수에 대해서 먼저 설명을 해보자면 

function sum(a, b) {
	return a+b;
}

이러한 간단한 함수를 예시로 들어보자면 a와b라는 파라미터의 값을 받아서 그 둘의 합을 리턴할때 a,b라는 파라미터의 값을 변경하지않고있음 -> 이경우가 pure하다.

 

impure함수를 보면

function withdraw(account, amount) {
	account.total -= amount;
}

이 함수를 보자면 account와 amount라는 파라미터를 받아서 account의 total이라는 값에서 amount라는 값을 빼는 함수임 쉽게 말하자면 은행 계좌에서 출금을 하는 함수. 이 경우를 보면 입력으로 받은 파라미터인 account의 값을 변경했으므로 impure한것임.

 

왜 이얘기를 했냐하면

리액트 공문에 모든 리액트 컴포넌트는 그들의 props에 관해서는 pure 함수 같은 역할을 해야함.

더 쉽게말하자면 리액트 컴포넌트는 props를 직접 바꿀순없고 같은 props에 관해서는 항상 같은 결과를 보여줄것!

 

jsx를 사용하면 키-값 쌍의 형태로 컴포넌트에 props를 넣을수있음

function App(props) {
	return (
    	<Profile
        	name="태영"
            introduction="안녕 난 태영이야"
            viewCount={1500}
         />
       );
 }

띄어쓰기 자꾸 왜이러는데...

App 컴포넌트가 나오는데 이 안에서 profile컴포넌트를 사용하고있음

이 profile컴포넌트 안에 name, introduction, viewCount라는 세가지 속성이 있는데 이 속성의 값이 모두 profile컴포넌트에 props로 전달되며, props는 아래와 같은 형태의 자바스크립트 객체가됨.

{
	name:"태영",
    introduction: "안녕 난 태영이야",
    viewCount: 1500
}

 주의할점은 props에 값을 넣을때에 문자열 이외에 정수, 변수, 그리고 다른 컴포넌트등이 들어갈 경우에는 중괄호를 사용하여서 감싸주어야함.

 

중괄호를 사용하는 예시를 들어보자면

funtion App(props) {
	return (
    	<Layout
        	width={2560}
            height={1440}
            header={
            	<Header title="태영의 블로그" />
             }
             footer={
             	<Footer />
             }
          />
       );
  }

 

컴포넌트는 함수 컴포넌트와 클래스 컴포넌트가 있음.

 

컴포넌트의 이름을 지을땐 항상 대문자로 시작.

소문자로 시작하면 DOM태그로 인식하기때문임.

 

이러한 컴포넌트들을 당연히 합성을 해서 만들수도있음.

function Welcome(props) {
	return <h1>Hello, {props.name}</h1>
 }
 
 function App(props) {
 	return (
    	<div>
        	<Welcome name="Mike" />
            <Welcome name="Steve" />
            <Welcome name="Jane" />
         </div>
      )
  }
  
  ReactDOM.render(
  	<App />
    document.getElementById('root')
);

이렇게 해버리면 App컴포넌트는 Welcome컴포넌트 세개를 포함하고있는 컴포넌트가됨.

 

반대로 복잡한 컴포넌트를 쪼개서 컴포넌트 추출을 할수도있음.

이걸 잘하면 컴포넌트의 재사용성이 올라감.

 

자자 가보자~

function Commnet(props) {
	return (
    	<div className="comment">
        	<div className="user-info">
            	<img className="avatar">
                	src={props.author.avatarUrl}
                    alt={props.author.name}
                  />
                  <div className="user-info-name">
                  	{props.author.name}
                  </div>
                </div>
                
                
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

여기에 이렇게 comment컴포넌트가 있는데 이건 내부에 작성자의 프로필 이미지,  이름, 댓글내용 ,작성일이 들어가있음.

이 컴포넌트에서 하나씩 컴포넌트들을 추출해보자.

 

우선 avatar컴포넌트 추출임.

comment 컴포넌트에서는 이미지태그를 사용하여서 사용자의 프로필 이미지를 표시하고 있음. 이부분을 추출할거임

 

function Avatar(props) {
	return (
    	<img className="avatar"
        	src={props.user.avartarUrl}
            alt={props.user.name}
          />
       );
  }

props에 기존에 있던 author보다 좀 더 보편적인 user사용. 이렇게 보편적인것을 사용해야 재사용성이 올라가기때문.

이제 이 추출한 컴포넌트를 다시 위에있는 코드에 적용한다면?

 

function Commnet(props) {
	return (
    	<div className="comment">
        	<div className="user-info">
            	<Avatar user={props.author} />
                  <div className="user-info-name">
                  	{props.author.name}
                  </div>
                </div>
                
                
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

이렇게됨.

이제 다음으로는 사용자 정보를 담고있는 부분을 추출해보자.

 

function UserInfo(props) {
	return (
    	<div className="user-info">
        	<Avatar user={props.user}>
            <div className="user-info-name">
            	{props.user.name}
            </div>
        </div>
      );
  }

사용자 정보를 담고있는 부분을 추출할때 이렇게 avatar컴포넌트도 같이 안에 들어가있는걸 볼 수 있다.

역시 아까와 마찬가지로 좀 더 보편적인 의미를 담고있는 user을 props에 사용

 

그럼 이 추출한 UserInfo 컴포넌트도 원래의 comment컴포넌트에 대입을 해보자

function Commnet(props) {
	return (
    	<div className="comment">
        	<UserInfo user={props.author} />
            
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

전보다 훨씬 간단해진걸 볼 수 있다.

이러한 컴포넌트 추출을 함에 있어서 기능단위로구분하는것이 좋고, 나중에 곧바로 재사용이 가능한 형태로 추출하는것이 좋다.

 

이렇게 comment 컴포넌트를 만들었는데 comment의 작성자 이름과 댓글 내용을 동적으로 변경해주기 위하여 props를 사용함.

근데 이렇게 하고 npm run start를 하면 작성자 이름과 댓글 내용이 나오지 않는데 그 이유는 그냥 name이랑 comment값이 정의가 안되어있어서 그럼 css는 걍 알아서 먹임

 

이런식으로 컴포넌트에 props값을 전달해주면

이렇게 뜸.

 

그럼 이제 데이터를 별도의 객체로 분리해서 동적으로 받아온 데이터를 표시가되게 만들어보자

왜냐면 저런식으로하면 어떻게 데이터를 받아와서 일일이 다 저렇게해 ㅇㅈ?

 

이렇게 예시로 더미데이터를 만들어서 이걸 map함수에 적용해서 comments에 있는 데이터들을 받아와서 컴포넌트에 대입시켜서 출력해주면댐.

 

 

'REACT' 카테고리의 다른 글

Life cycle and hook  (0) 2023.07.14
Shared state  (0) 2023.07.13
REACT  (0) 2023.04.29
React  (0) 2022.11.09
useRef  (0) 2022.07.28

기계학습이란?

 

어떤 컴퓨터 프로그램이 T라는 작업을 수행한다. 이 프로그램의 성능을 P라는 척도로 평가했을때 경험 E를 통해 성능이 개선된다면 이 프로그램은 학습을 한다고 말할 수 있다.

 

사례 데이터, 즉 과거 경험을 이용하여 성능 기준을 최적화하도록 프로그래밍하는 작업

 

성능을 개선하거나 정확하게 예측하기 위해 경험을 이용하는 계산학 방법들

 

왜 머신러닝인가??

 

인공지능이 탄생하면서 컴퓨터의 뛰어난 능력으로 사람이 어려워하는 일을 아주 쉽게할수있게됨.(곱셈을 고속으로 한다던지, 복잡한 함수의 미분과 적분을 척척함)

컴퓨터에 대한 기대감도 올라감(컴퓨터의 능력 과신)

 

초창기에는 지식 기반 방식이 주로되었음

예)구멍이 2개고 중간부분이 홀쭉하며 맨 위와 아래가 둥근 모양이라면 8이다.

지식기반에서 기계학습으로 인공지능의 주도권이 전화됨. 

이때 기계학습이란 통계적 측면을 고려한 데이터 중심 접근방식

 

과거의 데이터로부터 학습하여 정확한 예측을 하도록 스스로 예측 모델을 만드는 컴퓨터 알고리즘

𝐦𝐢𝐧 |𝓨+ − 𝓨−|

𝓨+: 미래에 더 잘하기위한 것

𝓨−: 과거에 경험한 일

여기서의 일반화문제, 과거 데이터에 최적 알맞게 되면서 경험해 보지 못한것도 정확하게 예측 가능한가?

 

훈련집합

가로축은 특징, 세로축은 목표치

관측한 점들이 훈련집합을 구성함.

무엇이 더 좋은 모델(수식)인가?

 

y=mx+b 어떤 m,b값을 선택해야 현재 데이터를 잘 묘사하는 모델이 나올까?

 

데이터를 어떻게 모델링할 것인가

눈대중으로 보면 직선을 이루므로 직선을 선택하자 -> 모델로 직선을 선택한 셈

직선 모델의 수식(2개의 매개변수 w와 b)

y= wx + b

기계학습은 가장 정확하게 예측할 수 있는, 즉 최적의 매개변수를 찾는 작업

처음엔 최적값을 모르므로 임의의 값에서 시작해서 점점 성능을 개선하여 최적에 도달

 

학습을 마치면 예측에 사용됨

최적의 매개변수를 w=0.5 b=2.0이라고하면 

예) 10.0 순간의 이동체 위치를 알고자하면 y=0.5x+2.0가 모델 수식이니까 x에 10을 넣어주면 y는 7.0이라 예측함.

이 기계학습의 궁극적인 목표는 훈련집합에 없는 새로운 샘플에 대한 오류를 최소화하는것

테스트 집합에 대한 높은 성능을 일반화 능력이라부름

 

수학적 방법론에 따른 기계학습 방법 구분

오차를 줄여가는 방식의 기계학습이 현대 딥러닝의 근간임

 

뉴럴 네트워크(신경망)

 

모수화된 예측모델은 랜덤 모수의 집합으로 초기화됨.

오류 함수는 훈련 데이터 세트에서 사례에 대한 예측을 할때 이 초기 모델이 얼마나 잘 수행되는지 판단하는데 사용됨.

오류 함수 값을 기반으로 매개변수가 반복적으로 조정되어 보다 정확한 모델이 생성됨

 

지도학습의 표기법

학습 알고리즘 - 선형 회귀 분석

목표: 주어진 교육 세트에 가장 적합한 매개 변수 찾기

 

선형 회귀 분석이란?

y = w₁x₁ + w₂x₂ + ... + wₙxₙ + b

여기서 x₁, x₂, ..., xₙ은 입력 변수의 특성(feature)이고, w₁, w₂, ..., wₙ은 해당 특성들의 가중치(weights)를 나타냅니다. b는 편향(bias)으로, 모델의 출력에 영향을 미치는 상수입니다. 목표는 주어진 데이터를 기반으로 적절한 가중치와 편향 값을 학습하는 것입니다.

 

파라미터가 얼마나 좋은지  측정

 

사무실 임대 데이터 세트의 크기 및 임대 가격 특징에 대한 산점도.
• 가능한 단순 선형 회귀 모델의 모음도 표시됩니다.
• 모든 모델에서 w[0]은 6.47로 설정됩니다.
• 위에서 아래로 모델은 w[1]에 대해 각각 0.4, 0.5, 0.62, 0.7 및 0.8을 사용합니다.

 

 

좋은 모델을 선별할 수 있는 조건은 원래 데이터와 오차가 어떻게 되는지 분석하는 것임.

목표: 주어진 교육 세트에 대한 비용 함수 최소화

 

그래서 어떻게 해결을 할까?

오차제곱합

 

x-y평면을 가중치 공간이라고 합니다.

표면을 오류 표면이라고 합니다.

교육 데이터에 가장 적합한 모형은 오차 표면의 최저점에 해당하는 모형입니다.(best fit)

 

최저점 - 최고의 fit

 

오차 표면의 최저점에 대한 공식적인 정의

이 점을 찾는 방법은 여러 가지가 있습니다.
•가장 유명하고 인기 있는 것은 경사 하강 알고리즘으로 알려진 안내 검색 접근 방식입니다(경사 하강법)

 

경사 하강법을 사용한 다변량 선형 회귀 분석

다변량 선형 회귀 모형

L2 손실(오차 제곱의 합)

범주형 특징 처리

의사 결정 경계

 

rpm 및 진동 형상의 산점도

삼각형은 결함이있고, 십자가는 좋음

 

의사결정 표면

오류표면의 기울기를 어떻게 계산할수있을까? 

항상 신뢰 예측(0또는 1)보다 민감한 예측이 바람직함.

 

매개 변수화된 분류자

로지스틱 함수 또는 시그모이드 함수

형식의 로지스틱 회귀 분석

weights: 선형 회귀 분석

 

로지스틱 회귀분석

• 분류 문제에 선형 회귀 모델을 사용할 수 있을까?
• 그렇다면 실제 값의 응답을 이진수에 매핑하는 방법은 무엇일까?
• 'Sigmoid' 기능 사용
• Sigmoid 지도는 [0, 1]에 해당합니다
• 파생상품

생성기 데이터 집합 예제

새로운 weight 업데이트 규칙

 

순수 수학 최적화와 기계 학습 최적화의 차이

 

기계  학습의 최적화는 단지 훈련집합이 주어지고, 훈련집합에 따라 정해지는 목적 함수의 최저점을 찾아야함

데이터로 미분하는 과정 필요 -> 오류 역전파 알고리즘

주로 SGD(스토캐스틱 경사 하강법)사용

 

매개변수공간의 탐색

학습 모델의 매개변수 공간

높은 차원에 비해 훈련집합의 크기가 작아 참인 확률 분포를 구하는 일은 불가능함

 따라서 기계 학습은 적절한 모델을 선택하고, 목적 함수를 정의하고, 모델의 매개변수 공간을 탐색하여 목적 함수가 최저가 되는 최적점을 찾는 전략 사용 -> 특징 공간에서 해야하는 일을 모델의 매개변수 공간에서 하는일로 대치한 셈

 

학습 모델의매개변수 공간 - 특징 공간보다 수배_수만배넓음

선형회귀에서 특징공간은 1차원, 매개변수 공간은 2차원 

mnist인식하는 딥러닝 모델은 784차원 특징공간, 수십만~수백만 차원의 매개변수 공간

이 그림의 개념도의 매개변수 공간 x^는 전역 최적해 x2와 x4는 지역 최적해

x2와 같이 전역 최적해에 가까운 지역 최적해를 찾고 만족하는 경우 많음

기계학습이 해야 할 일을 식으로 정의하면,

 

최적화 문제 해결

 

낱낱 탐색 알고리즘

차원이 조금만 높아져도 적용 불가능

예) 4차원 iris에서 각 차원을 1000구간으로 나눈다면 총 1000^4개의 점을 평가해야함

무작위 탐색 알고리즘

아무 전략이 없는 순진한 알고리즘

기계학습이 사용하는 전형적인 탐색 알고리즘

라인 3에서는 목적함수가 작아지는 방향을 주로 미분으로 찾아냄

 

경사 하강 알고리즘

 

배치 경사 하강 알고리즘

샘플의 그레이디언트를 평균한 후 한꺼번에 갱신

스토캐스틱 경사 하강 알고리즘

한 샘플의 그레이디언트(경사)를 계산한 후 즉시 갱신

라인 3~6을 한번 반복하는 일을 한 세대라 부름

 

다른방식의 구현으로는

 

퍼셉트론

구조: 입력층과 출력층을 가짐

입력층은 연산을 하지 않으므로 퍼셉트론은 단일 층 구조라고 간주

입력층의 i번째 노드는 특징벡터 x=(x1,x2,...,xd)^T의 요소 xi를 담당

항상 1이 입력되는 바이어스 노드

출력층은 한 개의 노드

i번째 입력층 노드와 출력층을 연결하는 에지는 가중치 wi를 가짐.

동작

해당하는 특징값과 가중치를 곱한 결과를 모두 더하여 s를 구하고, 활성함수 t를 적용

활성함수 t로 계단함수를 사용함으로 최종출력 y는 1또는 -1

 

2차원은 결정직선, 3차원은 결정 평면, 4차원이상은 결정 초평면

 

학습문제

지금까지는 학습을 마친 퍼센트론을 가지고 동작을 설명했는데

w1과 s2,w0가 어떤 값을 가져야 100% 옳게 분류할까?

그림에서는 2차원 공간에 4개의 샘플이 있는 훈련집합이지만 현실 세계는 d차원인 공간에 수백~수만개의 샘플이 존재

(예 mnist는 784차원에 6만개 샘플)

 

그렇다면 이 문제에서 어떻게 학습을 시킬것인가?

목적함수 설게

퍼셉트론의 매개변수를 w=(w0,w1,w2,....,wd)^T라고 표기하면 매개변수 집합은 @={W}

목적 함수를 J(@)또는 J(W)로 표기함

목적함수의 조건

J(W) >=0이다.

W가 최적이면 즉, 모든 샘플을 맞히면 J(W) =0이다.

틀리는 샘플이 많은 W일수록 J(W)는 큰값을 가진다.

이 식은 위에 세가지 조건을 만족하므로 퍼셉트론의 목적함수로 적합함(Y는 W가 틀리는 샘플의 집합)

왜 적합할까?

Y는 W가 틀리는 샘플의 집합임

Xk가 Y에 속한다면? 퍼셉트론이 계산한 𝐰^𝐓𝐱𝑘와 𝐱𝑘의 클래스를 뜻하는 𝑦𝑘는 부호가 달라야 함(원래 정답은 1 퍼셉트론의 예측이 틀렸다면 그 값은 -1이 되어야함. 클래스를 1,-1로 정의했다면)

이 조건을 만족하면 −𝑦𝑘 (𝐰^𝐓𝐱𝑘 )는 항상 양수

Y가 클수록 틀린 샘플이 많을수록 J(W)는 큰 양의 값을 가짐

만일 Y가 공집합이면? 모든 샘플을 맞힐 때이므로 값은 0이 나올것

 

그레이디언트 계산

가중치 갱신 규칙 𝚯 = 𝚯 − 𝜌𝐠를 적용하려면 그레이디언트 𝐠가 필요

이 식을 편미분하면,

이 편미분 결과를 가중치 갱신 규칙 𝚯 = 𝚯 − 𝜌𝐠 이 식에 대입하면,

 

퍼셉트론 학습 알고리즘

이 위에 방금 구한 식을 이용하여 학습 알고리즘을 쓰면

훈련집합의 샘플을 모두 맞출때까지 세대(라인3~9)를 반복함.

 

퍼셉트론 학습 알고리즘의 스토캐스틱 버전

 

다층 퍼셉트론

퍼셉트론은 선형 분류기라는 한계

선형 분리가 불가능한 밑에같은 상황에서는 일정한 양의 오류

예) XOR문제에서는 75퍼센트가 정확률 한계

 

민스키의 퍼셉트론

퍼셉트론의 한계를 지적하고 다층구조를 이용한 극복 방안 제시. 당시 기술로 실현 불가능

1974년 웨어보스는 박사 논문에서 오류 역전파 알고리즘 제안.

1986년 루멜하트의 저서에서  다층 퍼셉트론 이론 정립하여 신경망 부활

 

다층 퍼셉트론의 핵심 아이디어

 

은닉층을 둔다. 은닉층은 원래 특징 공간을 분류하는 데 훨씬 유리한 새로운 특징 공간으로 변환한다.

시그모이드 활성함수를 도입한다. 퍼셉트론은 계단함수를 활성함수로 사용하였는데 이 함수는 경성 의사 결정에 해당한다.

반면 다층 퍼셉트론은 연성 의사결정이 가능한 시그모이드함수를 활성함수로 사용한다.

연성에서는 출력이 연속값인데 출력을 신뢰도로 간주함으로써 더 융통성있게 의사결정을 할수있다

오류 역전파 알고리즘을 사용한다. 다층 퍼셉트론은 여러 층이 순차적으로 이루어진 구조이므로, 역방향으로 진행하면서 한번에 한층씩 그레이디언트를 계산하고 가중치를 갱신하는 방식의 오류 역전파 알고리즘을 사용한다.

 

특징 공간 변환

퍼셉트론 2개를 사용한 XOR문제의 해결

퍼셉트론 1과 퍼셉트론 2가 모두 +!이면 동그라미 부류이고 그렇지 않으면 네모 부류임

 

특징 공간 변환

퍼셉트론 2개를 병렬로 결합하면,

원래공간 X=(X1,X2)^T를 새로운 특징 곤간 Z=(Z1,Z2)^T로 변환

새로운 특징 공간 Z에서는 선형 분리 가능함.

 

 

퍼셉트론 1개를 순차 결합하면, 

새로운 특징 공간 Z에서 선형 분리를 수행하는 퍼셉트론3을 순차 결합하면, 다층 퍼셉트론이됨.

 

다층 퍼셉트론의 용량

3개의 퍼셉트론을 결합하면, 2차원 공간을 7개 영역으로 나누고 각 영역을 3차원 점으로 변환

활성함수 t로 계단함수를 사용하므로 영역을 점으로 변환

일반화하여, p개 퍼셉트론을 결합하면 p차원 공간으로 변환

 

 

활성함수

 

딱딱한 공간 분할과 부드러운 공간 분할

계단함수: 딱딱한 의사결정(영역을 점으로 변환)

나머지 활성함수: 부드러운 의사결정(영역을 영역으로 변환)

 

구조

입력층-은닉층-출력층의 2층 구조

d+1개의 입력노드(d는 특징의 개수), c개의 출력노드(c는 부류개수)

p개의 출력노드: p는 하이퍼 매개변수( 사용자가 정해주는 매개변수)

p가 너무 크면 과잉적합, 너무 작으면 과소 적합 

b는 입력층-은닉층-은닉층-출력층의 3층 구조

 

다층퍼셉트론의 매개변수(가중치)

입력층-은닉층을 연결하는 U1(𝑢𝑗𝑖^1 은 입력층의 i번째 노드를 은닉층의 j번째 노드와 연결)

은닉층-출력층을 연결하는 U2 (𝑢𝑘𝑗^2 는 은닉층의 j번째 노드를 출력층의 k번째 노드와 연결)

 

일반화하면 𝑢𝑗𝑖^𝑙 은 l-1번째 은닉층의 i번째 노드를 l번째 은닉층의 j번째 노드와 연결하는 가중치

입력층을 0번째 은닉층, 출력층을 마지막으로 간주

특징 벡터 X를 출력벡터 O로 매핑하는 함수로 간주할 수 있음

노드가 수행하는 연산을 구체적으로 쓰면, 

𝐮𝑗^1은 j번째 은닉 노드에 연결된 가중치 벡터 (식 (3.11)의 𝐔 1의 j번째 행) 

𝐮𝑘^2는 k번째 출력 노드에 연결된 가중치 벡터 (식 (3.11)의 𝐔 𝟐의 k번째 행)

 

다층 퍼셉트론의 동작을 행렬로 표기하면

 

은닉층은 특징 추출기

은닉층은 특징 벡터를 분류에 더 유리한 새로운 특징 공간으로 변환

현대 기계 학습에서는 특징학습이라함

 

오류 역전파 알고리즘

 

목적함수의 정의

훈련집합

특징벡터 집합 𝕏 = {𝐱1, 𝐱2, ⋯ , 𝐱𝑛} 과 부류 벡터 집합 𝕐 = {𝐲1, 𝐲2, ⋯ , 𝐲𝑛}

부류 벡터는 원핫 코드로 표현됨. 즉 𝐲𝑖 = (0,0, ⋯ , 1, ⋯ , 0)^T

설계 행렬로 쓰면,

기계학습의 목표

모든 샘플을 옳게분류하는 함수f를 찾는일

평균 제곱 오차로 정의

식 3.21를 알고리즘 형태로 쓰면,

 

 

feedforward and backpropagation

 

원칙


계산 기능(예: net, 활성화 기능)으로 forward
가중치 결정에 적용되는 구배를 계산하려면 backward

순전파와 역전파를 통해 딥러닝 학습

순전파는 주어진 데이터를 이용하여 결과를 예측

역전파는 결과의 오차를 이용하여 웨이트를 업데이트

 

역전파 알고리즘

1. 오차를 뒤로 보내어 웨이트를 업데이트하고

2. 업데이트된 웨이트로 다시 결과를 예측

3. 결과 예측과 데이터 사실 값의 오차가 0이 되도록 하는 것이 목표

4. 1~3과정을 반복하여 학습을 진행 - 최적 웨이트 찾는 최적화 과정

 

손실의 기울기

 

제곱 오차를 최소화 시킬 수 있는 값을 찾는 것이 목적

미분을 통해 제곱 오차 최소로 하는 값을 손쇱게 구해보자

SPA 장점

Optimizing performance

리액트에서 SPA(single page application)의 장점은 사용자 경험, 개발 효율성, 유지 보수성등이 있습니다. 이 SPA는 전체 페이지를 새로고침하지 않고도 빠르게 웹 어플리케이션을 개발할수있습니다. 이 SPA는 페이지간 이동이 없기때문에 애플리케이션의 복잡성이 낮아지고 변경사항을 쉽게 추적할수있습니다.

이러한 SPA는 초기 로드시간 검색엔진 최적화 메모리 사용등의 성능 문제가 있을수있습니다. 따라서 최적화기술들이 사용됩니다.

 

SPA 단점

초기로드시간: SPA는 초기 로드시간이 오래 걸릴 수 있습니다. 애플리케이션의 모든 자원을 다운로드하고 초기 렌더링을 위해 필요한 자바스크립트 파일을 다운로드하고 실행하여야하기 때문입니다.

검색엔진 최적화: SPA는 검색엔진 최적화가 어렵습니다. 검색엔진은 SPA의 동적인 콘텐츠를 인식하지 못하고, 페이지 url이 단일하므로 검색엔진에서 쉽게 인덱싱 되지 않을 수 있습니다.

보안: SPA는 XSS공격에 취약합니다 SPA는 동적으로 콘텐츠를 로드하기 때문에 제3자가 악성 스크립트를 삽입할수 있습니다.

브라우저 지원: SPA는 모든 브라우저에서 동작하지 않을 수 있습니다. 특히 오래된 브라우저나 모바일 기기의브라우저에서는 일부기능이 지원되지않을수있습니다.

메모리 사용량: SPA는 자바스크립트 코드가 클라이언트 측에서 실행되므로, 브라우저의 메모리 사용량이 높아질 수 있습니다. 이를 해결하기 위해 코드 스플리팅과 메모리 관리를 신경써야 합니다.

서버요청: SPA는 모든 자원을 최초에 한번 다운로드하고 이후에는 서버로 요청하지 않기 때문에 서버에서 변경된 데이터가 즉시 반영되지 않을 수 있습니다. 이를 해결하기 위해 서버와의 API통신을 통해 데이터를 주기적으로 가져와야 할 수 있습니다.

 

SSR

Next.js

 

SSR(server side rendering)은 서버 측에서 웹 페이지를 최초에 완전한 형태로 렌더링하여 클라이언트에게 보내주는 기술입니다. 일반적으로 SPA에서는 초기 로드시 모든 자원을 다운로드하고 자바스크립트를 실행한 뒤 동적으로 콘텐츠를 렌더링합니다 이는 초기 로드 시간이 오래 걸릴 수 있고, 검색 엔진 최적화가 어렵다는 단점이 있습니다. 하지만 SSR을 사용하면 서버에서 웹 페이지를 렌더링한 결과를 클라이언트에게 보내주기 때문에 초기 로드 시간이 줄어들고 검색 엔진 최적화도 개선됩니다. 또한 서버에서 데이터를 미리 가져와서 렌더링 할 수 있기 때문에 초기 데이터 로딩 시간도 단축됩니다.

NEXT.JS는 리액트 기반의 SSR웹 프레임 워크입니다. 이것을 사용하면 리액트 애플리케이션을 더 빠르고 개발자 친화적인 방식으로 개발할 수 있습니다.

Next.js의 주요 기능

서버 사이드 렌더링(SSR): Next.js는 서버 사이드 렌더링 기능을 제공하여 초기로딩 속도를 향상시키고 검색 엔진 최적화를 쉽게 할 수 있습니다.

코드 스플러팅: Next.js는 페이지별로 자동으로 코드를 분할하여 필요한 코드만 로드하여 초기 로딩 속도를 개선할 수 있습니다.

정적 사이트 생성: Next.js는 정적 사이트 생성 기능을 제공하여 서버리스 방식으로 정적 사이트를 생성할 수 있습니다.

hot reloading: 코드 수정 후 새로고침하지 않아도 브라우저에서 즉시 변경 사항이 적용됩니다.

기본적인 보안기능: next.js는 XSS및 CSRF(Cross site request forgery)공격에 대한 보안 기능을 내장하고 있습니다.

type script지원: next.js는 type script를 지원합니다.

쉬운 배포: next.js는 vercel이라는 클라우드 플렛폼에서 호스팅을 지원하여 쉽게 배포할 수 있습니다.

next.js는 리액트와 함께 사용할 수 있으며, 리액트 생태계와 호환성이 높아 리액트 개발자에게 더욱 익숙한 방식으로 개발할 수 있습니다.

 

CSR

CSR(client side rendering)은 클라이언트 측에서 자바스크립트를 이용해 동적으로 웹페이지를 렌더링하는 기술입니다. SPA에서 주로 사용됩니다.

CSR에서는 초기 로드시에 모든 자원을 다운로드하고 자바스크립트를 실행한 뒤, 동적으로 콘텐츠를 렌더링합니다. 이를 통해 사용자 경험을 향상 시킬수있습니다 예를들어 사용자가 특정 버튼을 클릭하면 해당 버튼과 관련된 콘텐츠만 다시 렌더링되어 화면 전체를 새로고침하지 않고도 빠르게 변경된 콘텐츠를 확인할 수 있습니다.

하지만 CSR은 초기 로딩 속도가 느리고 검색 엔진 최적화가 어려운 단점이 있습니다. 초기 로딩속도가 느린 이유는 초기에 모든 자원을 다운로드해야하고 자바스크립트를 실행해야 하기 때문입니다. 또한 검색엔진 최적화가 어려운 이유는 CSR에서는 초기 로드 시점에 웹 페이지가 비어있기 때문입니다. 이러한 문제를 해결하기 위해 SSR기술이 등장합니다.

 

React-Router-dom

react router dom 은 리액트 애플리케이션에서 라우팅을 다루기 위한 인기있는 라이브러리 입니다.현재 url경로를 기반으로 라우팅 및 네비게이션을 처리할 수 있도록, 라우트를 컴포넌트로 정의하고 렌더링하는 방식으로 선언적으로 처리할수 있게 해줍니다.

react router dom을 사용하려면 먼저 설치해줍니다.

npm install react-router-dom

설치를 완료했다면 해당 라이브러리에서 필요한 컴포넌트를 가져와서 라우트를 정의 할 수 있습니다.

import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

function App() {
return (
<Router>
<div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
</Switch>
</div>
</Router>
);
}

browser 컴포넌트를 사용하여 라우팅을 설정하고, switch와 route컴포넌트를 사용하여 경로에 따라 적절한 컴포넌트를 렌더링하도록 설정합니다 이렇게 설정된 라우팅을 통해 사용자가 url경로를 변경하면 해당 경로에 맞는 컴포넌트가 렌더링되게 합니다.

 

Route연결

Switch

react router dom의 switch 컴포넌트는 하위 route컴포넌트중에서 가장 먼저 일치하는 하나의 라우트만 렌더링하도록하는 컴포넌트입니다. 즉 url경로에 따라 렌더링할 컴포넌트를 선택하는데 switch는 이를 처리하는 라우팅 컴포넌트중에서 하나만 선택하여 렌더링하도록 해줍니다.

<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
</Switch>

이렇게 두개의 route컴포넌트가 있다고 가정해보면 사용자가 ‘/contact’경로로 이동하면 컴포넌트는 두번째 route컴포넌트에 일치하므로 contact컴포넌트를 렌더링합니다 반면 ‘/about’경로로 이동하면 첫 번째 route컴포넌트에 일치하므로 about컴포넌트를 렌더링 합니다.

<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route>
<NotFound />
</Route>
</Switch>

switch컴포넌트는 일치하는 라우트가 없는 경우에는 아무것도 렌더링하지 않습니다 이를 이용하여 404페이지를 구현할수있습니다.

위 코드에서 처럼 route컴포넌트는 path prop이 없는 경우이므로 어떤 경로와도 일치하지 않습니다. 따라서 일치하는 라우트가 없는 경우에는 ‘not found’컴포넌트를 렌더링하게됩니다.

 

Link

react router dom의 link컴포넌트는 사용자가 클릭할 때 url경로를 변경하고 새로운 페이지를 로드하지 않고도 라우팅할 수 있도록 해주는 컴포넌트입니다. 즉 애플리케이션에서 다른페이지로 이동할때 일반적인 앵커 태그’a’ 대신에 link컴포넌트를 사용하여 이동할 수 있습니다.

import { Link } from 'react-router-dom';

function MyComponent() {
return (
<Link to="/about">About Us</Link>
);
}

예를들어 다음과 같이 link컴포넌트를 사용하여 ‘/about’경로로 이동할 수 있습니다.

link컴포넌트는 일반적으로a태그같은 스타일을 가지며 마우스 포린터를 올리면 커서가 바뀌고 클릭하면 url로 경로가 변경됩니다. 그러나 페이지를 새로고침하지 않고도 url경로를 변경할 수 있기 때문에 페이지가 로드되지않고 애플리케이션이 더 빠르게 동작합니다.

 

Redirect

react router dom의 redirect컴포넌트는 사용자를 다른 경로로 리디렉션 시켜주는 컴포넌트입니다. 즉 url경로를 변경하고 새로운 페이지를 로드하여 리디렉션하는 기능을 제공합니다.\

redirect컴포넌트는 일반적으로 사용자가 인증되지않은 경우 로그인페이지로 리디렉션하는데 사용됩니다. 예를들어 다음과 같이 인증되지않은 사용자인경우 ‘/login’경로로 리디렉션 할 수 있습니다.

import { Redirect } from 'react-router-dom';

function MyComponent() {
const isAuthenticated = false;

if (!isAuthenticated) {
return <Redirect to="/login" />;
}

// 인증된 사용자의 경우 처리할 코드
return <div>Welcome!</div>;
}

 

History API

history api는 웹 브라우저의 세션기록을 조작하는 자바스크립트 인터페이스입니다. 이 api를 사용하면 브라우저의 url을 동적으로 변경하고 뒤로가기와 앞으로가기 버튼을 클릭하면 브라우저의 상태를 이전 또는 이후로 변경할 수 있습니다.

history api는 pushState(), replaceState(), go(), forward(), back() 등의 메서드를 제공합니다.

window.history.pushState({ page: "home" }, "Home", "/");

위 코드에서 page:home는 state object로, 브라우저의 상태를 나타내는 객체입니다. home은 새로운 history 항목의 title이며, /는 새로운 URL 경로입니다.

 

Dynamic routing

다이나믹 라우팅은 react router dom에서 동적으로 url을 생성하는 것을 말합니다. 이를 통해 특정 데이터 또는 id값을 url에 전달하고 동적으로 렌더링 할 수있는 페이지를 만들 수 있습니다.

예를들어 다음과 같이 /users/:id경로로 라우팅하는 route를 설정할 수 있습니다.

 

import { Route } from 'react-router-dom';
import User from './User';

function App() {
return (
<div>
<Route path="/users/:id" component={User} />
</div>
);
}

위 코드에서 :id는 경로 매개변수이며 /users/1, /users/2, /users/3과 같은 경로를 동적으로 생성할수있습니다

user컴포넌트에서는 props.match.params.id와 같은 방식으로 url매개변수를 읽어와 처리할 수 있습니다

import { useParams } from 'react-router-dom';

function User() {
const { id } = useParams();

return (
<div>
User ID: {id}
</div>
);
}

위 코드에서 useParam() hook을 사용하여 url매개변수를 읽어올 수 있습니다. 이를 통해 /users/1, /users/2, /users/3과 같은 동적 경로에 대응하는 페이지를 동적으로 렌더링 할 수 있습니다.

 

Nested routes

nested routes는 react router dom에서 하위 라우팅을 설정하는 것을 말합니다 즉 한 route내에서 다른 route를 중첩하여 사용하는 것입니다 이를통해 복잡한 ui를 구성하거나 중첩된 컴포넌트를 처리할때 유용하게 사용할수 있습니다

Nested routes를 설정하려면, Route 컴포넌트 내부에서 또 다른 Route 컴포넌트를 사용하면 됩니다. 이때, 중첩된 Route 컴포넌트에는 path prop을 부여해야 합니다.

예를들어 다음과 같이 /users경로에서 userList컴포넌트를 /users/:id경로에서 userdetail컴포넌트를 렌더링하도록 중첩된 라우팅을 설정할 수 있습니다.

import { Route, Switch } from 'react-router-dom';
import UserList from './UserList';
import UserDetail from './UserDetail';

function Users() {
return (
<Switch>
<Route exact path="/users" component={UserList} />
<Route path="/users/:id" component={UserDetail} />
</Switch>
);
}

 

파라미터

react router dom에서 파라미터는 url경로의 일부로 전달되는 값들을 의미합니다 예를들어 /users/1경로에서 1은 파라미터입니다

파라미터를 사용하려면 url경로에 파라미터를 나타내는 placeholder를 추가해야합니다 이를위해 : 기호를 사용하여 url경로의 일부를 변수로 표시합니다 예를들어 /users/:id 경로에서 id는 변수입니다

파라미터를 사용하기 위해, Route 컴포넌트에서 path prop을 사용하여 URL 경로를 설정할 때, 변수로 사용할 이름을 : 기호를 사용하여 지정합니다. 이때, 변수 이름은 식별자 규칙에 따라 유효한 이름이어야 합니다. 예를 들어, /users/:userId 경로에서 userId는 유효한 변수 이름입니다.

Route 컴포넌트에서 파라미터 값을 사용하기 위해서는, 컴포넌트의 props에서 match 객체를 사용합니다. match 객체는 URL 경로와 일치하는 라우트 정보를 포함하고 있으며, params 속성을 통해 파라미터 값을 가져올 수 있습니다.

import { Route, Link } from 'react-router-dom';
import UserDetail from './UserDetail';

function UserList(props) {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];

return (
<div>
<ul>
{users.map(user => (
<li key={[user.id](http://user.id/)}>
<Link to={’/users/${user.id}’}>{[user.name](http://user.name/)}</Link>
</li>
))}
</ul>
<Route path="/users/:id" render={(props) => <UserDetail id={[props.match.params.id](http://props.match.params.id/)} />} />
</div>
);
}

 

쿼리

쿼리(Query)는 React Router DOM에서 URL 경로의 끝에 ? 기호를 사용하여 전달되는 문자열 파라미터 값입니다. 쿼리 문자열은 key=value 형태로 작성하며, 여러 개의 쿼리 파라미터는 & 기호로 구분합니다. 예를 들어, /search?q=react&sort=popular경로에서 q와 sort는 쿼리 파라미터입니다.

Route 컴포넌트에서 쿼리 파라미터 값을 사용하기 위해서는, 컴포넌트의 props에서 location 객체를 사용합니다. location 객체는 현재 URL 정보를 포함하고 있으며, search 속성을 통해 쿼리 파라미터 값을 가져올 수 있습니다. 이때, search 속성의 값은 ? 기호를 포함한 전체 문자열입니다.

예를 들어, 다음과 같이 /search?q=react&sort=popular 경로에서 쿼리 파라미터 값을 가져와서 SearchResults 컴포넌트에서 사용할 수 있습니다.

import { Route } from 'react-router-dom';
import SearchResults from './SearchResults';

function SearchPage(props) {
return (
<div>
<form onSubmit={(e) => {
e.preventDefault();
const searchValue = e.target.elements.search.value;
props.history.push(’/search?q=${searchValue}&sort=popular’);
}}>
<input type="text" name="search" />
<button type="submit">Search</button>
</form>
<Route path="/search" render={(props) => <SearchResults query={new URLSearchParams(props.location.search).get('q')} sort={new URLSearchParams(props.location.search).get('sort')} />} />
</div>
);
}

 

MPA / SPA

MPA(Multi-page-application)는 여러 페이지로 이루어진 어플리케이션을 말합니다 즉 mpa는 사용자가 다양한 페이지로이동하면서 애플리케이션을 사용하는 전통적인 방식입니다. 반면에 리액트는 SPA(single-page application)를 지향합니다 SPA는 한개의 페이지로 이루어진 어플리케이션으로 새로운 페이지를 로딩할 필요없이 화면이 동적으로 바뀌는 것을 특징으로 합니다. SPA는 사용자 경험과 속도 측면에서 우수한 성능을 보여주기때문에 최근에는 많은 웹 어플리케이션이 SPA로 구현됩니다.

 

컴포넌트

클래스형 컴포넌트

 

리액트에서 클래스형 컴포넌트는 ES6의 클래스 문법을 사용하여 정의되는 컴포넌트 입니다. 클래스형 컴포넌트는 React.Component클래스를 상속받아서 만들어지며 render()메소드를 포함하고 있습니다.

다음 코드는 React.Component클래스를 상속받아 MyComponent라는 클래스형 컴포넌트를 정의합니다.

import React from ‘react’;

class MyComponent extends React.Component {

render() {
return <h1>Hello, World</h1>;
}
}

클래스형 컴포넌트는 다음과 같은 특징이 있습니다.

this.props를 사용하여 부모컴포넌트로부터 전달된 속성값에 접근할 수 있습니다.

state객체를 사용하여 컴포넌트 내부 상태를 관리할 수 있습니다.

this.setState()메소드를 사용하여 state를 업데이트 할 수 있으며

state가 변경될때마다 render()메소드가 다시 호출됩니다.

 

함수형 컴포넌트

 

함수형 컴포넌트는 리액트에서 컴포넌트를 정의하는 또 다른 방법입니다. 함수형 컴포넌트는 단순한 자바스크립트 함수로 정의되며, 입력값을 받아들여 UI를 반환합니다.

예를들어,

import React from ‘react’;

function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
}

이코드는 함수형 컴포넌트입니다.

props를 사용하여 부모 컴포넌트로부터 전달된 속성값에 접근할수있습니다.

useState()훅을 사용하여 컴포넌트의 내부 상태를 관리할 수 있습니다.

useEffect()훅을 사용하여 컴포넌트가 생성되거나 업데이트될때 필요한 작업을 수행할 수 있습니다.

함수형 컴포넌트는 클래스형 컴포넌트보다 더 간결하고 가독성이 높으며, 성능면에서도 우수합니다.

 

JSX 문법

 

javascript의 확장 문법으로 리액트에서 UI를 정의하는데 사용됩니다.

JSX는 javascript코드 내부에 XML형태로 작성되며, XML과 유사한 문법을 사용하여 UI를 표현합니다.

const element = <h1>Hello,world!</h1>;

이 코드는 jsx를 사용하여 h1요소를 렌더링합니다.

html과 비슷한 문법을 사용하여 리액트 어플리케이션을 작성할수 있습니다.

자바스크립트 식을 {}중괄호로 둘러싸서 jsx내부에 포함시킬수있습니다.(이를통해 동적인 ui생성가능)

jsx에서는 클래스 이름 대신 className속성을 사용합니다(jsx가 html이 아닌 자바스크립트이기 때문에)

 

Props / State

props:

props는 컴포넌트간에 데이터를 전달하는데 사용됩니다. 부모 컴포넌트가 자식 컴포넌트에게 속성값을 전달하면 자식 컴포넌트에서는 props를 통해 전달받은 값을 사용할 수 있습니다.

function MyComponent(props){

return <h1>hello {props.name}</h1>;

}

ReactDOM.render(<MyComponent name=”taeyoung” />, document.getElementById(’root’));

 

이 코드는 name이라는 props를 전달하고있습니다.

MyComponent 컴포넌트에서 props 객체를 받아서 {props.name}으로 전달된 name속성값을 출력하고 있습니다.

 

state:

state는 컴포넌트의 내부 상태를 관리하는데 사용됩니다. state를 사용하면 컴포넌트가 렌더링될때 동적인 ui를 생성할수있습니다.

state는 클래스형 컴포넌트에서 this.state를 통해 접근하고 this.setState()를 사용하여 업데이트 할 수 있습니다.

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>You clicked {this.state.count} times.</p>
<button onClick={() => this.handleClick()}>Click me</button>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById('root'));

MyComponent클래스형 컴포넌트에서 state객체를 생성하고, count 값을 0으로 초기화합니다. handleClick()메서드를 사용하여 count값을 증가시키고, this.setState()를 호출하여 state객체를 업데이트합니다. render()메서드에서는 this.state.count값을 출력하고, 버튼 클릭시 handleClick()메서드를 호출합니다.

 

Virtual DOM

virtual DOM은 브라우저의 실제 DOM과 유사한 트리구조로 이루어진 객체입니다 리액트는 상태가 변경될때마다 가상의 DOM을 생성하고 이전 가상 DOM과 비교하여 변경된 부분만 실제 DOM에 반영합니다.

이것은 DOM조작이 일어날때마다 브라우저가 전체 페이지를 다시 그리는 것을 방지하여 성능을 향상시킵니다 또한 리액트는 가상 DOM의 변경사항을 최적화하여 실제 DOM조작을 최소화하도록 합니다.

 

Reconciliation

RECONCILIATION는 리액트에서 가상 DOM을 사용하여 업데이트를 최적화하는 과정입니다. 리액트는 상태가 변경될때마다 새로운 가상 DOM을 만들고 이전 가상 DOM과 비교하여 변경된 부분만 실제 DOM에 반영합니다 이 과정에서 RECONCILIATION이 발생합니다.

Reconciliation은 리액트에서 성능 최적화를 위한 중요한 과정 중 하나입니다. 이를 통해 불필요한 렌더링 작업을 방지하고, 빠르고 효율적인 UI 렌더링을 달성할 수 있습니다.

 

Event handling

이벤트 핸들링은 웹 어플리케이션에서 사용자와 상호작용할 수 있는 방법중 하나입니다. 이는 사용자의 입력에 대한 응답으로 코드를 실행하는것을 의미합니다.

버튼클릭, 마우스이동, 키보드입력등의 이벤트 처리를 할수있습니다.

리액트에서 이벤트 처리는 일반적으로 JSX문법을 사용하여 처리됩니다. JSX에서는 이벤트처리기를 props로 전달하여 구성요소에서 이벤트를 처리합니다.

import React from 'react';

function Button() {
function handleClick() {
console.log('Button clicked');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}

이런식으로 버튼을 클릭할대마다 함수를 실행시킬수있습니다.

onClick prop을 사용하여 클릭 이벤트에 대한 처리기 함수인 handleClick을 전달합니다. 이벤트 처리기는 함수로 전달되며, 이벤트가 발생할 때마다 호출됩니다.

'REACT' 카테고리의 다른 글

Shared state  (0) 2023.07.13
React Foundation  (0) 2023.06.27
React  (0) 2022.11.09
useRef  (0) 2022.07.28
React virtual DOM  (0) 2022.07.28

그냥 파일을 읽어서 출력

import cv2 as cv
import sys

img = cv.imread('soccer.jpg')

if img is None:
	sys.exit('파일없음')

cv.imshow('soccer img',img)

cv.waitKey()
cv.destroyAllWindows()

rgb채널별로 디스플레이하기

import cv2 as cv
import sys

img = cv.imread('soccer.jpg')

if img is None:
	sys.exit('파일 찾으수없음')
    
cv.imshow('original',img)
cv.imshow('위왼쪽반",img[0:img.shape[0]//2,0:img.shape[1]//2,:}
#img[높이,너비,채널]
cv.imshow('가운데중간',img[img.shape[0]//4:3*img.shape[0]//4,img.shape[1]//4:3*img.shape[1]//4,:])

cv.imshow('r채널',img[:,:,2])
cv.imshow('g채널',img[:,:,1])
cv.imshow('b채널',img[:,:,0])

cv.waitKey()
cv.destroyAllWindows()

 

영상형태 변환하고 크기 축소하기

import cv2 as cv
import sys

img = cv.imread('soccer.jpg')

if img is None:
	sys.exit('파일이 존재하지 않습니다')

grayimg = cv.cvtColor(img,COLOR_BGR2GRAY)
grayimg_small = cv.resize(grayimg,dsize=(0,0),fx=0.5,fy=0.5)

cv.imwrite('grayimg',grayimg)
cv.imwrite('grayimgsmall',grayimg_small)

cv.imshow('원래 이미지',img)
cv.imshow('그레이 이미지',grayimg)
cv.imshow('작아진 그레이 이미지',grayimg_small)

cv.waitKey()
cv.destroyAllWindows()

 

감마보정하기

import cv2 as cv
import numpy as np

img = cv.imread('soccer.jpg')
if img is None:
	sys.exit('파일이 없음')
    
img=cv.resize(img,dsize=(0,0),fx=0.25,fy=0.25)

def gamma(f,gamma=1.0):
	f1=f/255.0
    return np.uint8(255*(f1**gamma))
    
gc = np.hstack((gamma(img,0.5),gamma(img,0.75),gamma(img,1.0),gamma(img,2.0),gamma(img,3.0)))
#np.hstack으로 그림 다 묶어줄때는 괄호 두개씩  써야댐

cv.imshow('감마보정이미지',gc)

cv.waitKey()
cv.destroyAllWindows()

 

히스토그램 평활화하기

import cv2 as cv
import matplotlib.pyplot as plt

img = cv.imread('soccer.jpg')

if img is None:
	sys.exit('파일을 찾을수없음')
    
grayimg = cv.cvtColor(img,BGR2GRAY)
#그레이스케일 이미지를 히스토그램 평활화 하지않고 출력
plt.imshow(grayimg,cmap='gray'),plt.xticks([]),plt.yticks([]),plt.show()

h = cv.calcHist([grayimg],[0],None,[256],[0,256])
plt.plot(h,color='r',linewidth=1),pltshow()

#그레이스케일 이미지를 히스토그램 평활화하여 출력
equal = cv.equalizeHist(grayimg)
plt.imshow(equal,cmap='gray'),plt.xticks([]),plt.yticks([]),plt.show()

h = cv.calcHist([equal],[0],None,[256],[0,256])
plt.imshow(h,color='r',linewidth=1),plt.show()

 

 

오츄알고리즘으로 이진화하기

import cv2 as cv
import sys

img = cv.imread('soccer.jpg')

t,bin_img = cv.threshold(img[:,:,2],0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print('오츄 알고리즘이 찾은 최적의 임계값=',t)

cv.imshow('r채널',img[:,:,2])
cv.imshow('r채널 이진화',bin_img)

cv.waitKey()
cv.destroyAllWindows()

 

 

컨볼루션 적용하기(가우시안 스무딩과 엠보싱)

import cv2 as cv
import numpy as np

img = cv.imread('soccer.jpg')
img = cv.resize(img,dsize=(0,0),fx=0.4,fy=0.4)

grayimg = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
cv.putText(gray,'soccer',(10,20),cv.FONT_HERSHEY_SIMPLEX,0.7,(255,255,255),2)
cv.imshow('오리지날',grayimg)

smooth = np.hstack((cv.GaussianBlur(grayimg,(5,5),0.0),cv.GaussianBlur(grayimg,(9,9),0.0),cv.GaussianBlur(grayimg,(15,15),0.0)))

cv.imshow('스무딩',smooth)

femboss = np.array([[-1.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,1.0]])

gray16 = np.int16(grayimg)
emboss = np.uint8(np.clip(cv.filter2D(gray16,-1,femboss)+128,0,255))
emboss_bad = np.uint8(cv.filter2D(gray16,-1,femboss)+128)
emboss_worse = cv.filter2D(gray16,-1,femboss)

cv.imshow(fghhhghghgf

 

에지 연산자 사용하기

import cv2 as cv

img = cv.imread('soccer.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

grad_x = cv.sobel(gray,cv.CV_32F,1,0,ksize=3)
grad_y = cv.sobel(gray,cv.CV_32F,0,1,ksize=3)

sobel_x = cv.convertScaleAbs(grad_x)
sobel_y = cv.convertScaleAbs(grad_y)

edge_strength = cv.addWeighted(sobel_x,0.5,sobel_y,0.5)

cv.imshow

역학

 

갈릴레이의 상대성 원리: 우주 공간에서 절대적으로 정지해 있는 것은 없다. 모든 운동은 절대적인 것이 아니고, 상대적이므로 본질적으로 정지 상태란 있을 수 없다.

즉, 기준이 되는 사람이 누구냐에 따라 정지한 상태가 될 수도 있고, 운동 상태일 수도 있다

 

뉴턴의 운동법칙

뉴턴의 운동법칙은 관성기준계에서 적용

길릴레이 변환에 대해 불변

시간과공간은 별개의 것

뉴턴의 만유인력 법칙: 질량이 있는 두 물체 사이에는 중력이라는 힘이 작용

 

맥스웰의 전자기학

전자기파의 존재를 이론적으로 예측

전자기파의 속도는 항상 일정하고, 그 값은 빛의 속도와 같다 -> 빛은 전자기파

 

에테르 존재에 대한 믿음

파동은 매질의 진동에 의해 에너지를 전달 

맥스웰에 의해 빛의 본질이 파동이라고 알려짐

빛을 전달하는 매질을 '에테르'라고 부름

지구는 에테르의 바다를 헤엄치고 있어서 태양빛이나 별빛이 지구에 도달한다고 생각

방향에 따른 빛의 속도에차이가 없다는 것을 측정

특수 상대성 이론

로렌츠가 맥스웰 방정식을 보존하는 변환식을 발견 -> 로렌츠 변환

아이슈타인이 특수 상대성 이론 발표

특수 상대성이론의 가정

상대성 원리: 모든 관성기준계에서 물리법칙은 같다.

빛 속도 불변의 원리: 자유공간에서 빛의 속도는 관측자나 광원의 운동에 관계없이 항상 일정하다.

고유 물리량

좌표계 내에서 물체와  함께 운동하는 관찰자가 측정한 길이, 시간, 질량을 고유 길이, 고유 시간,고유 질량이라고 한다.

동시성의 상대성: 어떤 관측자에게 동시에 일어난 일로 보이는 사건들이 다른 관측자에게는 동시가 아닐 수 있다.

 

시간 지연 효과

(정지해 있는 관측자가 본) 움직이고 있는 시계는 정지해 있는 시계의 시간보다 시간이 느리게 흘러간다.

실제 증거

미국의 과학자들이 제트 여객기에 원자시계4개를 싣고 지구한바퀴를 돈다음 실험실의 원자시계와 비교한결과 시계가 느리게 갔음을 확인 - 입자가속기 안의 입자들의 수명이 늘어남

 

길이 수축 효과

움직이는 막대의 길이는 정지했을때 측정한 막대의 길이보다 작아진다

 

움직이는 입자의 질량이 m이면 입자의 에너지는 E=mc^2

물체 속도의 한계 질량을 갖는 물체는 빛의 속도와 같아지거나 빛의속도를 초과할 수 없다.

물체의 속도를 증가시킬때 속도에 가까와질수록 물체의 질량이 무한대로 증가하여 점점 더 가속하기 어려워짐 ->

물체의 속도를 빛의 속도로 움직이기 위해서는 무한대의 에너지가 필요함으로 물체는 빛의 속도에 도달 할 수 없음

 

일반상대성 이론에 대한 갈망

특수 상대성이론은 관성기준계에 대한 운동만을 다룬다

가속도 운동을 하는 기준계에서 물체의 운동을 다루는 일반적인 이론은 무엇인가?

 

일반 상대성이론의 가정

일반화된 상대성원리: 가속계를 포함한 모든 기준계에서 물리학의 이론은 같은 꼴로 표현된다.

등가원리: 가속운동하는 기준계안에 있는 관측자는 자신이 느끼는 힘이 중력에 의한 것인지 아니면 가속운동하는 기준계에 의한 것인지를 구분할수없다

 

위로 가속하는 엘레베이터 안에서는 수평으로 지나가는 빛은 휘어져 보인다.

가속하는 엘리베이터와 중력이 미치는 엘레베이터에는 같은 물리법칙이 적용된다 - 등가 원리

등가원리를 적용하면 중력이 미치는 엘베 안에서도 빛은 휘어져 보일것이다.

정리하자면 빛은 항상 직진하기 때문에 빛이 휘어지는 것이 아니라 공간이 휘어진 것이다.

 

자유공간에서 일정한 속도로 움직이는 임의의 물체는 두점을 잇는 경로중에서 최단시간의 경로를 선택한다

-> 직선의 경로

중력이 작용하는 곳에서 빛의 경로가 휘어있다

-> 빛은 직선의 경로로 움직이지만 시공간이 휘어있기 때문에 빛의 진행경로가 곡선으로 왜곡된다.

 

아이슈타인의 방정식과 시간과 공간의 재해석

질량을 가지는 물체는 주위의 시공간을 휘게 만든다

빛이나 물체의 이동은 휘어진 시공간에서 최소 경로를 따라 움직인다.

우주 상수

아이슈타인이 팽창하지 않는 우주 모형을 얻기 위해 우주 상수를 방정식에 추가함

허블이 우주가 팽창한다는 사실을 발견하자 아이슈타인은 우주상수 철회

하지만 양자장론에 의하면 우주상수는 자연스럽게 존재함

그러나 이론적 계산결과보다 아주 작은 값의 우주 상수값이 측정됨 -> 우주상수문제

우주론에서는 우주상수가 우주의 가속 팽창에 기여 -> ACDM모형

 

우주 물질의 구성(우주상수(66~74%) 암흑물질(22~30%) 보통의 물질(4%))

 

일반 상대성이론과 물리현상

 

중력에 의해 빛의 경로가 휘어진다

항성에서 오는 빛은 태양처럼 무거운 질량을 가진 물체 근처에서 휘어짐

에딩턴이 최초로 관측함

중력렌즈 효과

수성의 근일점 위치 변화 설명

수성이 태양에 가장 가깝게 접근하는 근일점의 위치가 조금씩 변화하는 것을 관측

수성 주위에 또다른 내행성 가능성 고려 하지만 내행성은 존재하지 않음

아이슈타인이 일반상대론을 이용하여 수성의 근일점 이동을 정확히 설명.

중력이 강할수록 시간은 느리게 흘러감

높은 건물의 1층과 꼭대기 층에서의 원자시계를 이용하여 시간 측정(1층이 더 느림)

 

블랙홀과 중력파의 존재

블랙홀

존미첼과 피에르시몽 라플라스

뉴턴 역학을 기반으로 충분히 무거운 별의 경우 탈출속도가 광속보다 커 빛마저도 탈출할수없을것으로 추측-암흑성

 

카를슈바르츠 실트

일반 상대성 이론의 아이슈타인 방정식의 해를 구함

-> 사건의 지평선이 존재한다는 것을 발견

존 휠러에 의해 블랙홀이라 명명됨 

 

1971년 블랙홀로 예상되는 백조자리 X-1발견 그 이후 수많은 블랙홀 확인

 

1974 스티븐 호킹

블랙홀이 호킹복사를 하며 유한한 온도와 엔트로피를 갖는다는 증거를 양자이론을 적용하여 이론적으로보임

- 블랙홀 열역학의 시초

 

2020년 노벨 물리학상 수상자

로저 펜로즈 : 블랙홀 형성이 일반 상대성 이론의 확실한 예측이라는 것을 발견

라인하르트 겐첼, 엔드리아 게즈: 우리은하의 중심에 있는 초거대 질량 밀집성의 발견

 

 

웜홀

여행 가능한 웜홀에 대한 연구 - 킵손

현재 알려진 물질로는 웜홀이 만들어질 수 없음

하지만 양자이론에 의하면 이론적으로는 가능

 

중력파

시공간의 뒤틀림이 발생한 요동이 파동으로 전달

중력파 발생의 근원: 백색 왜성 또는 중성자별이나 블랙홀을 포함한 이중성계

 

중력파의 직접 검출

13억년 광년에 떨어진 곳에서 쌍성계를 이루고 있던 두개의 블랙홀이 충돌해 새로운 블랙홀이 되는 과정에서 생성

블랙홀의 질량은 각각 태양의 36배 29배

하나로 결합하여 태양보다 62배 무거운 블랙홀 이때 태양 3개분의 질량이 에너지로 전환되면서 중력파가 발생함

중력파의 발생

'space' 카테고리의 다른 글

우주물리학 - 원자  (1) 2023.04.21
우주물리학 - 우주관  (0) 2023.04.21

+ Recent posts