Full Stack Architecture :
。REST API를 구축해두면,Flexibility가 확보되어 REST API의Business logic을 각각의 Application(React App,Mobile App... etc)에 중복하여 구현할 필요가 없이 쉽게 재사용하여 구축이 가능.
Full-Stack Application :
- Front-End :
React를JavaScript의 Framework으로 활용하여 Front-End Application 구축.- Back-End : Spring Boot를 활용하여
REST API구축- DataBase :
H2 DB사용 후Postgres DB로 전환.- Security :
JWT Token을 사용한Spring Security활용
▶ Spring Boot로 구축된REST API에 연결되는React Application을 구축하여 브라우저에서 실행하기.
ES: ( ECMAScript ) :
。ECMA International의 ECMA-262 표준을 따르는 Scirpt 언어
▶ JavaScript는 해당 표준을 구현한 Script 언어! (JavaScript=ECMAScript)
▶ interface와 구현한 Class의 관계.
Node.js
。V8 JavaScriptEngine으로 빌드 된 JavaScript Runtime.
。JavaScript를 웹 브라우저로부터 독립하여 서버환경 구현
▶ JS 코드를 브라우저 없이 기기에서 바로 실행 가능.
。Runtime: 특정 언어가 구동되는 환경
npm( Node Package Manager ) :
。Node.js에서JS로 개발된 각종 사용가능한 모듈의 package를 설치, 업데이트 , 제거과정을 자동화하면서 관리 할 수 있는 도구.
npx( Node Package Executer )
。JavaScriptpackage를 설치할 필요 없이 직접 실행하게하는 패키지 실행기.
package.json:
。JavaScript의 Dependency를 정의하는 파일
。Package dependency 정보를 정의할 경우,npm에서 자동으로 다운로드.
▶ Spring의MavenorGradle과 유사.
ex ) Maven의pom.xml에 dependency를 정의할 경우 Maven이 자동으로 다운로드.npm을 활용하여 라이브러리 설치하기.
。npm을 이용하면 dependency를 직접 다운로드 및 버전관리 할 필요 없이 라이브러리를package.json파일에 dependency로서 정의하여 자동으로 설치 및 관리.
。PowerShell을 실행한 후cd "생성할폴더경로"를 통해 폴더 경로를 정의 후npm init을 입력하여 프로젝트 생성.
。package.json파일이 생성되며, package 이름 및 각종 설정을 설정한 후 ( 입력하지 않으면 default값이 적용 )yes를 입력하여 마무리.
。이후 pwd를 눌러 현재 작업디렉토리를 확인한 후 이동 시package.json이 생성되있음을 확인 가능.
。package.json를Visual Studio Code로 드래그할 경우 내용이 처음 설정한대로 정의되있음을 확인 가능.
package.json에 JavaScript Library를 dependency로 추가하는 방법
。jQuery Library를 추가할 경우,PowerShell에npm install jquery를 입력하여 설치될 경우 자동으로package.json에서 해당 dependency로서 정의됨.
。또한, 작업디렉토리에 생성된 폴더node_modules에서 jquery 폴더가 생성되있음을 확인 가능.
。package.json에jQuerydependency가 추가됨. ("jquery": "^3.7.1")
▶ JavaScript 코드에서 바로jQuery를 사용 가능!
React.js :
。Meta(현 Facebook)에서 오픈소스로 공개한 UI( User Interface )를 구축하기 위한 Front-End JavaScript Library
▶ 주로 Web SPA Application 구축에 사용됨.
。동일 성격의 다른 Library로는Angular, Vue.js가 존재.
。React Component의 조합으로 Application을 제작.
▶React Component의 재사용으로 개발과정을 단순화 및 유지보수가 용이함.
SPA( Single Page Applications ) :
。하나의 HTML로 구성된 Web Application으로서, 서버에서 필요한 데이터만 비동기로 받아와서 동적으로 현재 화면에 다시 Rendering하는 방식.
ex) To-do Web Application에서 To-do를 하나 추가할 경우, 전체 페이지가 새로고침되어 변경되는것이 아닌, 페이지에서 변경되는 해당 부분만 새로고침되어 변경됨.
。Application과 상호작용 할때마다 서버에 요청하며 전체 HTML 화면을 받아오는게 아닌, 화면 렌더링을 Local PC에서 생성하므로 빠르게 화면전환이 가능!
React Native
。Facebook에서 제작한 오픈소스 모바일 application framework.
。다른 언어를 사용할 필요없이JavaScript로 IOS와 Android 모바일 Application을 동시에 구축이 가능한 크로스 플랫폼.
▶ 기본 Android Application은Kotlin,Java를 사용하고, IOS는Obect-C와Swift의 언어로 개발하는게 일반적이었음.
- React의 Background Logic
Virtual DOM:HTML을 가상으로 만든UI표현
- 1. 브라우저에서 Page 로딩 시
React는 해당 Page의Virtual DOM을 생성하여 메모리에 저장
- 2.
React Component에서State를 활용해 해당Virtual DOM을 Update하는 코드를 작성
。실제 HTML의DOM을 업데이트하는게 아닌,Virtual DOM을 업데이트.
。기존Virtual DOM에서 수정된 버전의Virtual DOM이 생성됨.
▶ 단일React Component에서 2개의Virtual DOM이 생성.
- 3. React가 기존의
Virtual DOM과 수정되어 생성된Virtual DOM간의 변경사항을 파악하여HTML DOM과 동기화하여 HTML Page에 반영.
。React Component의Status가 조금이라도 변경되면React는Virtual DOM으로부터 변경사항을 감지하여 실제 HTML의DOM와 동기화를 수행.
DOM( Document Object Model ) : 문서객체모델 Javascript-DOM
。Browser가HTML문서를 해석 시 생성하는 Tree구조의 객체 모델.
▶ HTML요소를 동적으로 제어하여JavaScript객체처럼 조작할 수 있는 Model
DOM tree:HTML Element를Javascript객체처럼 사용 시 객체를 트리구조로 표현.
React Component
。React로 구축된 Application의UI를 구성하는 독립으로 재사용가능한 최소 단위.
▶HTML,CSS,JavaScript를 하나의 최소단위로 묶어서 효율적으로 관리 가능.
▶ 보통 React Application은 Component를 수백 개 포함.
각 Page( =View)는Menu, Header, Footer, Log-in등 여러 Page가 존재.
▶ React Application을JS파일로 모듈화하여 각 Page를React Component로 분리하여 재사용성을 높임.
。React Application에서 처음 load되는React Component는src/index.js의<App />(App() Component).
▶ 다른React Component를 생성 시 보통 해당src/app.js에서 구현된App() Component의 자식 Component으로 생성.
React Component고려사항
Class Component보다는Functional Component+Hook를 사용- 각 자식 Component는 목적(
Menu, Header, Footer, Log-in)에 따라 각 Module에 구분되어 분리되어야 좋다.React Component의 이름은 항상 대문자로 시작해야한다 :PastelCase
▶HTML태그는 (ex.<div>) 항상 소문자를 사용.
JSX는 닫는 태그가 필수적(</태그>)JSX에서의 최상위 태그는 오직 한개만 허용return (JSX코드)에서 2줄 이상의JSX를 반환하는 목적으로 소괄호 사용.<div className="CSS클래스명">:JSX에서는 태그에 Class 속성 지정 시className=""로 지정
▶HTML에서는class=""속성과 동일.
▶ 상위태그요소에 CSS 적용 시 내부의 자식태그에도 해당 CSS Styling이 상속되어 적용됨.
- React Component의 종류
- Functional Component
。가장 많이 사용하는 방식.
。useState,useEffect등의Hook를 사용 가능.
▶Hook를 사용하여State를 구현 가능.
Hook:Functional Component에서State를 추가 및 Life-Cycle를 관리할 수 있게 하는 기능.
▶React 16.8에서 도입되어Class Component보다 더 간단하고 직관적인 코드를 작성.
。useNavigate(),useContext()등의react hook를 사용하여 객체 생성 시Component내부 Scope에서 선언.
▶Component의 특정함수 내에서 객체를 선언하면 안된다.function First(){ return ( <div className="First"> First() Component </div> ) }const First => (){ return ( <div className="First"> First() Component </div> ) }▶ 화살표함수로 구현이 가능하다
Functional Component에서 자식 Component를 매개변수로 받아서 return하는 방법
활용 :<Context객체.Provider>,React 보호
。자식Component를 Component의{ 자식요소 }의Object객체로 매개변수로 받아들인다.function First(){ return ( <div> <Parent> <Child/> </Parent> </div> ) } function Parent( { children } ){ return ( <div> Parent / { children }</div> ) } function Child(){ return ( <div>child</div> ) }。
<Parent><Child/></Parent>에서Child Component는Parent Component의 자식 Component이므로,Parent Component의 매개변수로<div>child</div>를 가져올 수 있다.
- Class Component
。import {Component} from 'react'를 통해 React Framework에서 Component를 import한 후 Class에 상속하여 사용.
。React 16.8이전에는State를 사용가능한 장점으로 자주 사용됨.
▶ 현재는Functional Component + Hook로 대체.import {Component} from 'react' class Second extends Component{ render() { return( <div className="Second"> Second() Component </div> ) }; }
- React Component의 특징
- 재사용성 , 독립성
。기존 Web Application은MVC방식으로 각Model,View,Controller간 의존성이 높아 재사용이 어려운 단점이 존재.
▶React Component는MVC의View를 독립적으로 구성하여 재사용이 가능하며, 해당React Component를 통해 새로운React Component를 구축 가능.
- 동적 렌더링
。props와state를 활용하여 동작.
JSX( Javascript XML ) :
const element = <h1>Hello, world!</h1>;
。React에서 VIEW(UI)를 작성하기 위해Javascript를 확장한 문법.
▶Javascript의 모든 기능이 포함됨.
。Javascript코드 내부에서HTML태그를 작성하여 동적기능 부여
▶ React Component가HTML,JS를 별도 파일로 인위적으로 분리하는게 아닌, 둘다 포함하는 특성을 통해 사용 가능.
。<div className="CSS클래스명">:JSX에서는 태그에 Class 속성 지정 시className=""로 지정
▶HTML에서의class=""속성과 동일.
▶ 해당 태그에 CSS 적용 시 내부의 태그에도 해당 CSS Styling이 상속되어 적용됨.
。JSX는 브라우저에서 실행할 수 없으므로Babel을 통해Javascript로 변환하여 브라우저에 전달.
。JSX는 닫는 태그(</태그>)가 필수적이고,Functional Component에서 return하는 최상위 태그는 오직 한개만 허용
▶ 복수 이상의 태그를 return 하는게 아닌, 단일 태그 내부에 복수 태그를 정의하여 return을 수행.return ( // JSX 코드 시작 <> // 복수의 태그를 단일 태그로 묶어서 return하며 빈태그 <>도 사용가능. { true && <div>true</div>} // true이므로 <div>true</div>를 반환. <div>안</div> <div>녕</div> <FirstComponent/> </> );。
return ( JSX )코드에서 소괄호()를 사용하는 이유?
▶ 한줄만 작성할 경우 없어도되나, 2줄 이상의 복잡한JSX를 반환하는 목적.
。JSX에서는 빈태그 (<>)도 사용 가능.
。{ boolean && JSX코드 }
Component의return ()에서 해당boolean이true인 경우, JSX코드를 반환하는 구문.
ex)return ( { true && <div>true</div>} )→ Page에 true를 반환.
Babel: Babeljs
。최신JavaScript를 브라우저가 이해할 수 있는Javascript코드로 변환할 수 있는compiler.
▶JSX에 대해서도Javascript코드로 변환할 수 있는 기능을 제공.
。오래된 브라우저에서도 최신버전의Javascript또는JSX를 실행 가능.
▶ 브라우저에 대하여 버전별Javascript의 호환성을 보장.
▶JSX코드로 작성된 내용을Javascript내용으로 변환.
- React Component의 요소
View
。React Component가 실제로 렌더링하는UI
。JSX코드로 작성되며 사용자에게 보이는 요소로 구성.
Logic
。React Component가 Data를 처리하고 동작하는 부분
▶JSX로 작성하여 event handler , API호출등의 Logic들이 구현.
。onClick:<button onClick={increment}>increment</button>
JSX에서<button>태그의onClick이벤트를 통해 Javascript 함수 사용 시onClick={JS함수명}으로 작성.
▶ 기존HTML에서는HTML태그에 Javascript 함수 사용 시onclick="JS함수명()"으로 문자열과 매개변수를 같이 표현해야했으나,JSX에서는 중괄호에 JS함수명만 기입하여 활용.
Styling(CSS)
。CSS를 사용하여Component의JSX를 통해 구현된HTML태그에 디자인을 적용.
JSX에 CSS를 적용하는 방법
JSX태그의style속성에 정의
- 태그의
style={스타일링Object객체}에 직접 스타일링 코드를 작성.<button style={{backgroundColor:"#00a5ab"}}>속성에 직접명시</button>
Object객체로서 스타일링 코드를 작성하여style={Object객체}으로 적용.
。value는 문자열 형식으로 작성.
。key에서 설정할 스타일명은 기존CSS의 스타일명에서-부분 뒤에 있는 문자열을 대문자로 표현.
ex)font-size▶fontSizeconst btnStyle={ fontSize:"16px", backgroundColor:"red" } <button style={btnStyle}>style속성에 배열로명시</button>
CSS파일을 import하여className="css클래스명"정의
。CSS 코드를 작성하여JSX모듈에서 import하여 css코드를 활용. (import 'CSS경로')/* Counter.css */ .countBtn{ text-align:cetner; background-color:green; font-size:16px; padding : 15px; margin:10px; color:white; border-radius: 30px; }// test.jsx import './Counter.css' export default function test(){ return( <button className="countBtn">increment</button> ) }。
JSX모듈에 import한Counter.css내부의.countBtn{스타일링정보}를 통해 button에 스타일링을 적용.
State:
。특정 React Component 내부에서 관리되는 동적데이터
。과거의React에서는Class Component에서만State를 포함할 수 있었지만, 현재는Hook기능을 통해Function Component에서도 State를 포함할 수 있다.
▶ React에서는useStateHook를 사용하여 상태를 변경 가능.
。React Componentinstance는 고유의State를 가지며 여러개의State를 가질 수 있다.
。React Componen간State공유가 가능하다.
。Controlled Method : 사용자가Form element로 입력한 변수 값을Component State로서 유지 가능.
Hook:Functional Component에서State를 추가 및 Life-Cycle를 관리할 수 있게 하는 기능.
▶React 16.8에서 도입되어Class Component보다 더 간단하고 직관적인 코드를 작성.
useState(초기값):Const [ 현재State값, StateUpdate함수 ] = useState(초기값)
import {useState} from 'react';를 통해 React Framework에서 import.
。React의Hook의 일종으로서, 매개변수로 State초기값을 전달하여 Component의State를 추가 및 관리 시 사용.
▶Functional Component에서도State를 관리하도록 설정.
。StateUpdate함수(값):현재State값을 특정값으로 설정.
▶StateUpdate함수(0)으로 선언하여 Component State의 초기화를 수행 가능.
。Functional Component에서useState활용 시 함수 내부에서 Component를 지칭하기위해this를 선언할 필요가 없다.
。현재State값과StateUpdate함수를 반환하며StateUpdate함수로현재State값변경 시 해당 State의 Component가 다시 비동기로 Rendering.
▶현재state값은 직접 수정하면 안되고 반드시StateUpdate함수를 활용하여 수정.// useState(초기값)을 통해 구조분해로 [현재State값 , StateUpdate함수] 도출 const [state,StateFunc] = useState(0) StateFunc( state+1 // state는 1로 update. )。
State값의 변경은 즉시 적용이 아닌 비동기적으로 처리됨.
▶ 버튼을 2번 눌러 2번StateUpdate함수를 호출해도 비동기적으로 처리됨으로현재state값은 한번만 증가할 수 있다.
State를 사용하는 이유와 React 표현 원리
StateUpdate함수를 통해State값을 Update하면 자동으로React Component(=VIEW)도 Update
。React Component에서State를 사용하는 경우State변경 시React에 의해 초기 Page loading 시 생성된Virtual DOM과State에 의해 변경되어 생성된Virtual DOM간의 변경사항을 감지한 후 실제HTML의DOM과 동기화하면서React Component를 자동 Update
▶ 기존의HTML element는HTMLPage를 표현하는DOM Tree의 각각의 Node로 표현되며 해당HTML Element를 Update할 경우,DOM도 함께 Update하는 코드를 작성해야하는 비효율로 코드의 복잡성 증가.
useReducer(reducer , 초기값State)
const [state, dispatch] = useReducer(reducer, initialState);
useState()처럼React의State를 관리하는Hook
▶useState보다 복잡한 State logic을 관리 시 사용.
reducer:State Update함수
▶(state, action)=>{new State}
action: 어떤 action을 수행할 지 결정하는 Object.
▶type,payload를 포함.
dispatch:reducer에 Action을 보내는 함수
▶action에 해당하는type을 전달 시 해당action의state값이 전달됨.
▶dispatch({ type: "ACTION_TYPE", payload : 전달값 })
- 예제 :
Global State관리import React, { createContext, useReducer, useContext } from "react"; const initialState = { count: 0 }; const CounterContext = createContext(); // State Update 함수 function reducer(state, action) { switch (action.type) { case "INCREMENT": return { count: state.count + 1 }; case "DECREMENT": return { count: state.count - 1 }; default: return state; } } export function CounterProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState); // 자식 Component에게 state와 dispatch를 전달 // return ( <CounterContext.Provider value={{ state, dispatch }}> {children} </CounterContext.Provider> ); } export function useCounter() { return useContext(CounterContext); }。
Context에Global State지정import React from "react"; import { CounterProvider } from "./CounterContext"; import Counter from "./Counter"; export default function App() { return ( <CounterProvider> <Counter /> </CounterProvider> ); }。Component 위계설정
import React from "react"; import { useCounter } from "./CounterContext"; export default function Counter() { const { state, dispatch } = useCounter(); return ( <div> <h2>Count: {state.count}</h2> <button onClick={() => dispatch({ type: "INCREMENT" })}>+</button> <button onClick={() => dispatch({ type: "DECREMENT" })}>-</button> </div> ); }자식 Component에서 Context를 통해 State의 Update 수행
Props: Property :
。React Component간 데이터를 동적으로 전달하는Read-only속성
▶One-Way Data Flow: 부모 Component에서 자식 Component로 단일방향 데이터 전달
▶ 읽기전용 : 부모 Component에서 전달되는props를 자식 Component에서는 수정이 불가능.
▶ 동적전달 : 부모 Component에서 전달된props가 변경된 경우 자식 Component로 전달된props도 자동으로 update.
。단일React Component는 여러개의Props를 가질 수 있다.
▶ 다수의Props를 다른React Component로 전달 가능.
。Props는 부모 Component에서 구현된 function을 자식 Component로 전송할 수 있다
▶ 자식 Component는 부모 Component의 함수를 참조하지 못하므로,Property를 통해 전달하여 자식 Component에서 사용이 가능하다.function App() { function Func1(){ return ( <div>Parent Component Function</div> ) } return ( <div className="App"> // 부모 Component : Property 전달 // Component에 props로 전달할 값을 태그 속성으로 작성. <PracticingProp property1="lee" property2={Func1}/> </div> ); } // 자식 Component : 부모 Component에서 전달한 문자열과 함수를 포함한 Property 수신 function PracticingProp({ property1, property2 }){ // 부모 Component(= App())에서 전달된 props를 구조분해하여 매개변수로 할당. return <div> {property1} // lee {property2} // <div>Parent Component Function</div> </div> }。부모 Component에서
props작성 시<Component명 key1="value1" , .../>형식으로 자식 Component로 전달.
▶ 부모 Component의Props는 객체(Object) 형태로 전달된다.{ key1: 'value1', ...}
。자식 Component에서function Component명(임의의props이름){ 임의의props이름.key1 }로 매개변수에 부모Component의 객체Props를 수신.
▶ 구조분해(Deconstruction) 활용 :function Component명({key1,key2, ...}){ key1 }로 매개변수에 중괄호({ })를 활용하여Object객체가 아닌 구조분해된key:value로 가져오는게 좋다
특정Component.propTypes:
。React에서 Component가 전달받는 props의 값형식을 정의하기 위해 사용.
。Component의 특정Props에 들어갈 수 있는 값의 Type을 제한.
▶특정Component.propTypes = { props변수명 : PropTypes.제한조건 }의Object객체로 설정하여 해당 Component의Props의 제한조건 설정.
PropTypes.제한조건: 해당 프로퍼티를 통해 Componentprops의 조건을 제한할 수 있다.
▶import PropTypes from 'prop-types'로 import 하여 사용.import PropTypes from 'prop-types'; const MyComponent = ({ name, age, isActive }) => { return ( <div> <h1>{name}</h1> <p>Age: {age}</p> <p>Status: {isActive ? 'Active' : 'Inactive'}</p> </div> ); }; // Component property의 제한조건을 추가. MyComponent.propTypes = { name: PropTypes.string.isRequired, // 문자열 (필수) age: PropTypes.number, // 숫자 (선택사항) isActive: PropTypes.bool // 불리언 (선택사항) };
- 이후 부모 Component쪽에서
<MyComponent name="문자열" age="문자열2" isActive={true} />로 전달 시propTypes.number에 의해 오류 발생.
PropTypes종류
。PropTypes.string: 문자열
。PropTypes.number: 숫자
。PropTypes.bool: boolean
。PropTypes.array: 배열
。PropTypes.object: 객체
。PropTypes.func: 함수
。PropTypes.any: 모든 타입
특정Component.defaultProps:
。React에서 Component가 전달받는 props의 초기값을 설정하기위해 사용.MyComponent.defaultProps = { name: "lee", age: 27, isActive: true };▶ 이후 부모 Component쪽에서
<MyComponent/>만 전달해도Props의 초기값이 자동으로 반영.
- Controlled Component : 활용
。React Component의State를 이용하여State와HTML Formelement(<input>등 )의DOMvalue를 동기화하여 제어하는 Component.
。입력 field에 입력한 value가React State로서 관리되며 value가 변화할때마다onChange이벤트를 통해State도 같이 동기화되어 Update.
▶Controlled Component를 설정하면서 사용자가Form element로 입력한 변수 값을Component State로서 유지 가능.
DOM value:HTML태그로서<input value="값">등Form자체의value
。사용자가 입력 field에 입력할때마다onChange이벤트로State를 상시 Update할 수 있다.
Controlled Component선언하는 방법 Input 속성
。Component의state와<input>의onChange,value속성을 활용해야한다.
▶import {useState} from 'react'를 선언하여 State사용.
。const [ 현재State값, StateUpdate함수 ] = useState(초기값)을 선언하여JSX의 입력 Form element<input value={현재State값}>을 설정하여 Binding.
。<input onChange={함수}>를 설정하여 해당onChange event를 매개변수로 받는 함수를 구현 및 내부에StateUpdate함수를 활용해event객체.target.value를 설정하여현재State값이 변경되도록 설정.
event객체.target:onChange이벤트를 수행한<input>의 JS객체를 지시.// Contorlled Component로 설정하기위해 State를 선언 및 Form element와 Binding을 수행. // [현재State값, StateUpdate함수] = useState(초기값) const [ username, setUsername ] = useState("wjdtn"); // 현재State값을 <input>의 onChange event로 trigger되어 변경하는 함수 생성. function changeUsername(evt){ // StateUpdate함수로 state값 설정. // evt.target.value : `onChange` 이벤트를 수행한 `<input>`의 value setUsername(evt.target.value) console.log(evt.target.value) } return ( {/* State와 Form Element를 Binding 하기위해 Form element의 value와 onChange 이벤트를 State와 관련된 기능으로 구현. */} <input type="text" value={username} onChange={changeUsername} /> )
▶onChange이벤트를 통해 입력 field의 값을 변경할때마다State도 동기화되어 즉각 Update가 수행됨.
React Context: Context 활용
。 React에서Context API를 통해Component Tree전체에 대하여Global State를 전달
。React Component들이props를 전달하지 않아도 데이터를 공유할 수 있게하는 역할을 수행.
▶Props Drilling방지
Props Drilling: 중간 Component가 불필요한props전달.
。Context의Global State를 통해React Application의Login State유지 등의 작업을 수행 가능.
Context관련 기능
import { Context관련기능 } from 'react'
createContext():
export const Context객체 = createContext();
。React에서Global State를 관리할때 사용하는Context객체를 생성하는Hook
▶ 해당Context객체는Component Tree전체에Global State를 전달하기 위한Context API가 구현됨.
▶ 다른 Component에서 Context를 참조하기위해Context객체앞에export를 선언.
<Context객체.Provider>:
。Global State를 제공
value={{ State변수 }}:
。Context를 통해 데이터를Component Tree로 전달하는 역할을 수행.
▶value속성에 전달할 데이터를 정의하면 모든 자식 Component가 데이터에 전역적으로 접근할 수 있음.
。value속성 설정 시 다른 Component에서useContext(전달된Context객체)를 통해 새로운Context객체생성 시{ State변수 : State변수값 }으로 생성됨.
useContext(전달된Context객체):
。Context의 데이터를 직접 가져오는 역할의React Hook
▶ 다른JS파일로부터 export된Context객체를 매개변수로 전달받아 새로운Context객체를 생성.
。 새로 생성된Context객체는<기존Context객체.Provider value={{State변수}}>를 통해 전달된State값을Object객체형식으로 포함. ({ State변수 : State변수값 }
▶ 해당 방식으로 모든 자식 Component에서 Context의 데이터를 전역 데이터로서 접근 가능.
。Context를 전달 시props를 활용한 전달방식을 사용하지 않아도된다.
- React에서
Routing
。Client가 브라우저에서 URL을 전달 시 해당 URL에 Mapping된 Component를 Rendering하는 기능을 의미.
▶SPA상에서는 페이지를 새로고침하지 않고도 페이지 전환처럼 보이게 할 수 있다.
React Router DOM:
。React Application에서 URL에 따라 Component를 Rendering하는Library
。Client-side Routing으로 페이지 새로고침 없이 빠르게 페이지 전환.
。URL 경로에 따라 Component를 Rendering.
。History API를 활용해 브라우저의 뒤로가기 / 앞으로가기 지원
。PowerShell실행 후React SPA Application이 존재하는 경로로 설정 후npm install react-router-dom을 입력하여 dependency를 설치하여 활용.
▶React SPA Application경로의package.json에 다음처럼"react-router-dom": "^7.2.0"dependency가 구현.
useEffect(콜백함수, [ Dependency List ]): API 호출 시 활용 사례
import { useEffect } from 'react'
。Functional Component에서Side effect를 처리하는데 사용하는React Hook
▶ Component의 Rendering 후 실행되는 코드를 정의 시 사용.
。API 호출,Event Listener추가,Timer설정 ,State변화 감지 등 작업에 활용.의존성배열 :
Dependency List:
。useEffect의 2번째 인자에 선언.
。정의안하는경우 : 모든 Rendering 시 마다 콜백함수 실행.
▶ 해당 API 호출 등의 작업을 Rendering할때마다 반복하므로 무한으로 사용.
。빈 배열[]:React Component가 처음 렌더링 시 한번만 콜백함수 실행.
。[ 특정 변수 ]: 특정 변수가 변경시마다 콜백함수 실행.
useRef():
。React Hook종류 중 하나로서, Component의 Rendering과 무관하게 값 유지 및DOMElement를 직접 참조 시 사용됨.
▶ 값을 저장하는 역할을 수행하지만, 값을 변경해도 Component는 Re-Rendering하지 않는다.
npm명령어
。PowerShell에서 React Application의 Directory 경로에서 실행
。주로React,Vue,Next.js등의 Framework에서 활용됨.
npm start:
。Node.js에서 개발모드로 Application을 실행.
。개발 모드로 실행시, 변경사항을 바로 적용하여 Feedback을 확인 가능.
npm test:
。watch (감시) mode에서 Unit Test를 실행.
npm run build:
。Node.js에서src/에 존재하는 소스코드(Javascript,Typescript,CSS등 )를 압축(minified) 및 최적화하여 배포(Production Deployable) 가능한 상태로 build하여 package 생성.
▶ React Application 개발 시 사용
▶ build 된 경우dist/또는build/폴더에 결과물 생성.
。디렉토리 내 많은js,css파일이 존재하여 배포 될 경우 생성된 build 디렉토리 내 단 3개의js,css파일로 생성됨.
▶ 해당 3개의js,css파일만으로 Application을 배포하여 실행이 가능.
npm install:
。Node.js에서 해당 Project에 특정 dependency를 설치.
ex)npm install --save react-router-dom
Visual Studio Code 명령어
- Toggle Explorer : Ctrl + B
。Explorer( 좌측 폴더트리구조 )창을 토글하여 숨기고 코드부분을 확장이 가능.- 파일 검색 : Ctrl + P
React Application 생성하기
Create React App
。ReactSPAApplication 생성 시 사용.
。Node.js의 최신버전을 사용해야 사용가능.
PowerShell에서package.json, node_modules, package-lock.json이 존재하는 폴더에 경로 설정
cd "C:\Users\LG\Desktop\Web Programming\FullStack"
npx create-react-app Application이름을 입력하여 React Application 생성
。해당 경로에Create React Apppackage를 실제로 설치하지 않았지만,npx를 이용하여 실행이 가능.
npx( Node Package Executer ) :JavaScriptpackage를 설치할 필요 없이 직접 실행하게하는 패키지 실행기.
。다음 내용이 도출되면 성공적으로React Application이 구축되었으며 경로내에 해당Application이름의 Directory가 생성.
。cd Application이름경로를 입력하여 디렉토리 내로 경로를 변경 후npm start입력 시 생성된 React Applicaton이 실행되며 브라우저에서는 로컬 URLhttp://localhost:3000/로 연결.
。ctrl+c를 눌러서 Server를 종료할 수 있다.Application 생성 중 발생하는 에러
~\Roaming\npmERR Path Error 발생 시
。package.json가 설치된 해당 경로를 환경변수로 추가.
network read ECONNRESET이 발생할 때 해결 방법
。PowerShell에 다음 구문을 입력 후 재시도.npm config set registry http://registry.npmjs.org/
Create React App을 통해 생성된 React Application 둘러보기
。Visual Studio Code를 실행한 후 해당 Application의 디렉토리로 경로 설정.
。npm start로 실행 후 코드를 변경하면 npm이 자동으로Create React App을 통해 Application을 Build하여 브라우저에서 Rendering.
。 public 폴더 내index.html실행 시 실행중인http://localhost:3000/Page의 html을 확인 가능.
ex )<title>Todo App</title>로 수정 시 해당 Local URL tab의 이름이 변경됨.
- React Application 구조
。Package.json: dependency를 정의하는 파일
。node_modules:package.json에 의해 정의된 dependency를npm이 다운로드하여 저장하는 디렉토리.
。index.html,index.js,App.js: React Application을 구현 시 활용되는 파일.
public/index.html:
。초기 HTML Page를 정의하여 React Application 실행 시 웹 브라우저에 먼저 로드됨.
。<div id="root"></div>를 포함하며 해당 태그에App Component로서index.js가 호출됨.
src/index.js:
。React Application을 초기화 및App Component를 렌더링하는 Module( =js파일 ).
▶App Component로서index.html에 의해 호출되어 Application을 동적으로 렌더링
。src/index.css: Application의VIEW전체에 대한Styling정보를 포함.const root = ReactDOM.createRoot(document.getElementById('root')); // index.html의 <div id="root"></div>로 접근. root.render( <React.StrictMode> // App Component 정의 <App /> // App.js 의 App() Component를 가져옴. </React.StrictMode> );
<App />:
。src/App.js의App() Component가 load되는 부분.
▶ 해당 태그의 양식은<Component이름/>으로 작성
▶src/App.js모듈의App() Component와 자식 Component는 해당 구문을 통해 브라우저에 표현됨.
src/App.js:
。App() Component의 코드를 포함하는 Module.
▶ Page에 load되는 실제 내용이 포함.
。다른 Component 생성 시App Component의 자식으로 생성하는 방식.
▶function App()Component의 자식 Component 생성 및App()Component의 계층구조에 포함!
。src/App.css: 해당 App Component에 대한Styling정보를 포함.
。src/App.test.js: 해당 App Component에 대해서Unit Test를 수행하는 Module.
▶ Spring의 경우,src/main/java에production code,src/test/java에test code가 따로 분리되어 존재하지만, JavaScript는production code와test code가 함께 존재import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer"> My Todo Application Updated </a> </header> </div> ); } export default App;。해당 Component의
<div>태그 내용 수정 시 다음처럼 수정됨.
- React Component 생성하기
。App.jsModule 내에서 React Component 작성해보기.
▶ 차후 Component를 개별의 모듈로 구분.
。React를 코드 작성 시JSX코드로 작성.
。CSS스타일링 시 Component의 태그는className="CSS클래스명"으로 설정.
▶<div className="App">설정 시src/App.css에 존재하는.App{css코드}적용
▶ 해당 태그에 CSS 적용 시 내부의 태그에도 해당 CSS Styling이 상속되어 적용됨.
▶ 이때 Compile 시 발생하는 오류는Node.js의npm start를 실행한 콘솔창에 지시됨.
App.js내부에서App()Component의 자식 Component 생성 및 표현
。생성할 React Component는function App()Component의 자식 Component.
- 자식 Component : 함수형 Component
function 함수명(){내용}생성
。함수형 Component 구축 시,function을 선언하여 함수형식으로 작성.
。Component의return(html태그요소)은 소괄호 내부에 html태그요소를 작성하여 해당 Component의 일부로서 return.// App() Component의 자식 Function Component // Component 생성 시 function으로 선언. function First(){ return ( <div> First() Component </div> ) }
- 자식 Component : Class형 Compoennt
Class 클래스명 extends Component {내용}
。React Framework의Component를 상속하는 Class 형식으로 작성.
▶import {Component} from 'react'를 통해 Component를 import.
。Method에return(html태그요소)를 구현하여html태그요소를App()Component에 return.
。render method: Component의 일부로 Page에 표현할 내용을 return.
▶ 현재는 함수형 Component + Class형 Component 로 대체됨import {Component} from 'react' // App() Component의 자식 Class Component // React Framework의 Component를 상속. // Rendering Method를 통해 태그요소를 return. class Second extends Component{ render() { return( <div> Second() Component </div> ) }; }
App()Component
。자식 Component를VIEW에 표현하려면App()Component의 계층 구조에 포함되어야함.
▶App()Component의<div></div>내부에<자식Component이름/>선언.
。<div className="App">설정 시src/App.css에 존재하는.App{css코드}적용
▶ 상위태그요소에 CSS 적용 시 내부의 자식태그(<First/>, <Second/>)에도 해당 CSS Styling이 상속되어 적용됨.
▶ CSS Styling 지정 시 HTML태그에 스타일링을 지정해야하며, 자식 Component는 CSS Styling이 적용이 안된다// App() Component import './App.css'; function App() { return ( <div className="App"> App() Component <First/> <Second/> </div> ); }import './App.css'; import {Component} from 'react' // App() Component function App() { return ( <div className="App"> App() Component <First/> <Second/> </div> ); } // App() Component의 자식 Function Component // Component 생성 시 function으로 선언. function First(){ return ( <div> First() Component </div> ) } // App() Component의 자식 Class Component // React Framework의 Component를 상속. // Rendering Method를 통해 태그요소를 return. class Second extends Component{ render() { return( <div> Second() Component </div> ) }; } export default App;
。다음처럼App.js의App() Component에 자식 Component가 포함되어 Page에 표현됨.
。이때 각각의 자식Component를 모두App().jsModule에 작성하는게 아닌,JSModule별로 구분하여 사용하는게 좋다.
。또한 Class형 Component보다는Functional Component를 사용하는게 좋다
React Component고려사항
Class Component보다는Functional Component+Hook를 사용- 각 자식 Component는 목적(
Menu, Header, Footer, Log-in)에 따라 각 Module에 구분되어 분리되어야 좋다.React Component의 이름은 항상 대문자로 시작해야한다 :PastelCase
▶HTML태그는 (ex.<div>) 항상 소문자를 사용.
JSX는 닫는 태그가 필수적(</태그>)JSX에서의 최상위 태그는 오직 한개만 허용return (JSX코드)에서 2줄 이상의JSX를 반환하는 목적으로 소괄호 사용.<div className="CSS클래스명">:JSX에서는 태그에 Class 속성 지정 시className=""로 지정
▶HTML에서는class=""속성과 동일.
▶ 상위태그요소에 CSS 적용 시 내부의 자식태그에도 해당 CSS Styling이 상속되어 적용됨.
- 경로상 각 Component를
src/components/경로 아래에.jsx파일 생성하여 구분
。각각의 자식 Component는 목적(Menu, Header, Footer, Log-in)에 따라 각 Module로 구분하여 분리.
▶ 분리된 모듈에서export default Component명을 작성하여 다른 모듈에서 사용가능하도록 설정.
- React Component 코드를 포함할
.jsxModule 생성 및App.js에서 활용
。src/components/특정디렉토리경로 아래에 React Component 코드를 포함한.jsx파일을 생성.
。export Component명,import Export한Component명 from '컴포넌트경로'활용.// src/components/practice1/First.jsx // export를 통해 해당 Component를 다른 모듈에서 import하여 사용가능하도록 설정. export default function First(){ return ( <div> First() Component </div> ) }// src/components/practice2/Second.jsx // export를 통해 해당 Component를 다른 모듈에서 import하여 사용가능하도록 설정. export default function Second(){ return ( <div> Second() Component </div> ) }。
export Component명의 선언하는 위치는 자유.
▶export function Component명(){}또는function Component명(){} export Component명import './App.css'; // 다른 React Component를 포함하는 모듈에서 Component를 import. import First from './components/practice1/First'; import Second from './components/practice2/Second'; // App() Component function App() { + return ( <div className="App"> App() Component <First/> <Second/> </div> ); } export default App;。이때, Import할 Component의 수가 많아지면 상단의 구문이 매우 복잡하므로, 이를 중계해서 처리하는
.jsx파일을 하나 더 생성하여 처리하면 깔끔하다.// Assemble.jsx // Named Import import {First, Second} from './practice1/First' // Default Import import Third from './practice2/Third' import Fourth from './practice2/Fourth' export default function Assemble(){ return( <div> <First/> <Second/> <Third/> <Fourth/> </div> ) }// App.js import './App.css'; import Assemble from './components/Assemble' // App() Component function App() { return ( <div className="App"> <Assemble/> </div> ); } export default App;。
App.js에 import한 Component들을 중간에Assemble.jsx모듈을 하나 생성하여 정리하여 깔끔하게 정리.
- Component의
export , import활용 례
。 Component를 포함하는 Module에서 선언하여 해당 Component를 다른 module에서 사용가능하도록 설정.
export default Component명:
。모듈에서 기본적으로 export할Default Component선언.
▶ 다른 모듈에서 참조 시import Component명 from '모듈경로'로 중괄호{ }생략.// 단일 Component를 Export. export default function First(){ return ( <div> First() Component </div> ) }
export Component명:
。모듈에서 다른 모듈로 복수 이상의 Component를 Export할 경우의 Component에 선언.
。 동일한Module이내에 존재하는 Component를 참조 시에도 해당Component는 export가 선언되어있어야한다.
▶ 다른 모듈에서 받을때는import { Compnent명, ... }의 중괄호로 받아서 활용.// 복수의 Component를 Export. export function First(){ return ( <div> First() Component </div> ) } export function Second(){ return ( <div> Second() Component </div> ) }.
import Export한Component명 from '컴포넌트경로':
。defalut import:import Export한Component명 from '컴포넌트경로'
。특정모듈의export default가 선언된 Component를 Export할 경우의 import를 정의.import First from './components/practice1/First';
named import:import { Component명1, Component명2 , ... } from '모듈경로':
。특정 Module의 복수 이상의 Component를 import할 경우 중괄호 ({ }) 로 수신.
▶ import에서 중괄호를 사용하지 않는 경우default import로서export default가 선언된 Component만 import.
▶{ Component명 }이 선언된 경우export default Component를 import하지 못한다.import {First, Second} from './components/practice1/First';
JSX에JS변수 전달하여 표현하기
。동적인 값을 표현하기 위한 방법.
▶ JS 변수를 중괄호({ })를 이용해<div>{변수명}</div>로JSX코드 내부에서 표현.import './App.css'; const kv = { name:'KF16', address:{ address1:'강원도 원주시' }, properties:["naver","kakao","instagram"], func : ()=>{ kv.properties.map((property)=>{ console.log(property) }) } } function App() { return ( <> <div className="App"> {kv.name} </div> <div> {kv.address.address1}, {kv.func()} </div> </> ); } export default App;。
const kv라는key:value배열을 생성 후,JSX코드에서 중괄호 안에 key의 value를 표현.
▶ JavaScript의key:value배열은JSON Format과 유사.
▶key:value배열은 함수를 포함할 수 있다.
![]()
배열.map(람다식):
。람다식의 매개변수를 배열의 요소로 받은 후 순회하면서 람다식에서 구현된 기능을 수행.
▶ 실무에서 자주사용.const kv = { properties:["naver","kakao","instagram"], func : kv.properties.map((property)=>{ return property; }) } kv.func
- 리액트 실습 :
CSS와State를 활용하여 카운터 Application 구축
。css코드를 import하여className="CSS클래스명"으로 CSS 스타일링 적용..countBtn{ text-align:cetner; background-color:green; font-size:16px; padding : 15px; margin:10px; color:white; border-radius: 30px; border-color:black; border-width:5px; } .count{ font-size:150px; padding:20px; }。
onClick:<button onClick={increment}>increment</button>
JSX에서<button>태그의onClick이벤트를 통해 Javascript 함수 사용 시onClick={JS함수명}으로 작성.
▶ 기존HTML에서는HTML태그에 Javascript 함수 사용 시onclick="JS함수명()"으로 문자열과 매개변수를 같이 표현해야했으나,JSX에서는 중괄호에 JS함수명만 기입하여 활용.
。State:Hook( = useState )를 활용한Functional Component에서 상태( = 데이터 )를 저장.
▶useState(초기값)을 통해 반환되는현재State값과StateUpdate함수에서StateUpdate함수로 State 변경 시 해당 State의 Component가 다시 Rendering
▶현재state값은 직접 수정하면 안되고 반드시StateUpdate함수를 활용하여 수정.import './Counter.css' import {useState} from 'react' export default function Counter(){ // useState(초기값)을 통해 구조분해로 [현재State값 , StateUpdate함수] 도출 const [state,StateFunc] = useState(0) function increment(){ StateFunc( state+1 ) } ; function decrement(){ StateFunc( state-1 ) } return ( <div className="Counter"> <div className="count">{state}</div> <button className="countBtn" onClick={increment}>increment</button> <button className="countBtn" onClick={decrement}>decrement</button> </div> ) }。
JSX에 변수는 중괄호{ }로 반영.
。현재State값의 변경은 즉시 적용이 아닌 비동기적으로 처리됨.
React Componentinstance는 고유의State를 갖는다
。동일한 Component를 instance로서 2개 구현 시 독립적인State값을 가진다.function App() { return ( <div className="App"> <Counter/> <Counter/> // 자식 Component의 instance를 2개 구현 </div> ); } export default App;
Props활용하여 각각의 Component Instance의 증감값을 다르게 설정.
Props:React Component간 데이터를 동적으로 전달하는Read-only속성
。부모 Component에서props작성 시<Component명 key1="value1" , .../>형식으로 자식 Component로 전달.
▶ 부모 Component의Props는 객체(Object) 형태로 전달된다.{ key1: 'value1', ...}
。자식 Component에서function Component명(임의의props이름){ 임의의props이름.key1 }로 매개변수에 부모Component의 객체Props를 수신.
▶ 구조분해(Deconstruction) 활용 :function Component명({key1,key2, ...}){ key1 }로 매개변수에 중괄호({ })를 활용하여Object객체가 아닌 구조분해된key:value로 가져오는게 좋다.import './App.css'; import Counter from "./components/counter/Counter" function App() { return ( <div className="App"> <Counter number={1}/> <Counter number={2}/> <Counter number={3}/> </div> ); } export default App;。부모 Component( =
App())에서 각각의 자식 Component instance( =Counter())에 재각각 다른Props값을 전달.// Counter.js import './Counter.css' import {useState} from 'react' // 부모 Component에서 전달한 Property를 매개변수에 구조분해하여 수신. export default function Counter({number}){ // useState(초기값)을 통해 구조분해로 [현재State값 , StateUpdate함수] 도출 const [state,StateFunc] = useState(0) function increment(){ StateFunc( state+number ) } ; function decrement(){ StateFunc( state-number ) } return ( <div className="Counter"> <div className="count">{state}</div> <button className="countBtn" onClick={increment}>{"+"+String(number)}</button> <button className="countBtn" onClick={decrement}>{"-"+String(number)}</button> </div> ) }。부모 Component에서 전달한
props인number를 매개변수로 구조분해를 통해 전달 받은 후 증감값에 반영
- 。부모 Component의
Props인number의 값을 각각 다르게 설정하여 동일한 자식 Component로 전달하여 각각의 instance 생성.
▶ 동적으로Props값 전달 시 각각의 Component instance의 증감값이 다르게 반영됨.
。 각각의 Component instance의State는 고유하므로,현재State값이 각각 독립적으로 저장됨.
。Props는Read-only이므로, 부모 Component에서 전달된Props의 값을 자식 Component에서 수정이 불가능.
Props
。React Component간 데이터를 동적으로 전달하는Read-only속성
▶One-Way Data Flow: 부모 Component에서 자식 Component로 단일방향으로 데이터 전달.
▶ 읽기전용 : 부모 Component에서 전달된props를 자식 Component에서는 수정이 불가능.
▶ 동적전달 : 부모 Component에서 전달된props가 변경된 경우 자식 Component로 전달된props도 자동으로 update.
- Component의
Props에 들어갈 수 있는 값 형식 제한 / 초기값 설정
특정Component.propTypes:
。React에서 Component가 전달받는 props의 값형식을 정의하기 위해 사용.
。Component의 특정Props에 들어갈 수 있는 값의 Type을 제한.
▶특정Component.propTypes = { props변수명 : PropTypes.제한조건 }의Object객체로 설정하여 해당 Component의Props의 제한조건 설정.
PropTypes.제한조건: 해당 프로퍼티를 통해 Componentprops의 조건을 제한할 수 있다.
▶import PropTypes from 'prop-types'로 import 하여 사용.
특정Component.defaultProps:
。React에서 Component가 전달받는props의 초기값을 설정.
▶ 부모 Component에서props를 정의 안해도 자식 Component에서props초기값이 자동으로 적용.import {useState} from 'react' import PropTypes from "prop-types" // PropTypes import export default function Counter({num}){ const [state,StateFunc] = useState(0) function increment(){ StateFunc( state+num ) } ; function decrement(){ StateFunc( state-num ) } return ( <div className="Counter"> <div className="count">{state}</div> <button className="countBtn" onClick={increment}>{"+"+String(num)}</button> <button className="countBtn" onClick={decrement}>{"-"+String(num)}</button> </div> ) } // Counter Component의 number props의 값형식을 숫자형으로 제한 Counter.propTypes = { num:PropTypes.number.isRequired, } // Counter Component의 props의 초기값 설정 Counter.defaultProps = { num : 1, };▶ 이후
App()Component에서<Counter number="문자열"/>전달시 오류 발생.
- Component를 계층적 구조로 표현 및 전체 카운트를 재는 Component를 추가
。Component의 위계를App()-TotalCounter()-Counter()로 설정.
。자식 Component에서는 부모 Component의 field를 참조할 수 없다.
▶ 부모 Component에서Props를 통해 자식 Component로 Function을 전달.
<자식Component 함수명={함수명}>// App.jsx import './App.css'; import TotalCounter from "./components/counter/Counter" function App() { return ( <div className="App"> <TotalCounter/> </div> ); } export default App;// Counter.jsx import './Counter.css' import {useState} from 'react' export default function TotalCounter() { // TotalCounter 고유의 State const [totalstate,totalFunc] = useState(0); function TotalCount(num){ totalFunc(totalstate+num) } return ( // 부모Component의 함수를 property로서서 자식Component 전달 <> <div style={{fontSize:"100px",color:"blue"}}>{totalstate}</div> <Counter num={1} TotalCount={TotalCount}/> <Counter num={2} TotalCount={TotalCount}/> <Counter num={3} TotalCount={TotalCount}/> </> ); }; // 부모 Component로부터 증감값과 함수를 포함한 Property를 매개변수에 구조분해하여 전달 function Counter({num, TotalCount}){ // Counter의 고유의의 State function increment(){ TotalCount(num) // 부모 Component State값 감소 } ; function decrement(){ TotalCount(-num) // 부모 Component State값 감소소 } return ( <div className="Counter"> <button className="countBtn" onClick={increment}>{"+"+String(num)}</button> <button className="countBtn" onClick={decrement}>{"-"+String(num)}</button> </div> ) };。자식 Component( =
Counter())의 State는 필요 없으므로 관련 구문은 모두 삭제.
。부모 Component ( =TotalCounter())의 함수TotalCount(num)를property를 이용해함수명={함수명}을 입력하여 자식 Component로 전송.
。 자식 Component ( =Counter())에서 해당 함수와 증감값을property로서 매개변수에 구조분해하여 수신하여 활용.
▶ 자식 Component에서 부모 Component의 함수를 사용하면서 부모 Component의State값이 변화.
。최상단 부모 Component( =App())은 자식Component ( =TotalCounter())에서 Return한 VIEW를 표현.
- 부모 (
TotalCounter()) Component의 State값 (totalstate)이 자식 (Counter()) Component에서 자식 Component에서property로 전달한 부모 Component의 함수 (TotalCount(num))이 동작하면서 변화.
Chrome : React Developer Tools
。Chrome에서React Component의 계층구조를 확인하는 목적으로 사용.
。각 Component의Props와State를 확인 및 편집이 가능.
검사-Components탭에서 다음 사항들을 확인할 수 있다.
!
。Rendering된 React Component의 계층정보를 확인 가능.
。추가적으로props와state정보를 확인 할 수 있으며 해당 값을 편집 가능.
▶ 해당 사진은props로서 부모 Component로 부터props로 전달받은 증감값(num)과 함수(TotalCount())를 지시.
react-dom@19.0.0(Virtual DOM) ▶createRoot()▶App▶TotalCounter▶Counter순으로 렌더링 되고있음을 관측 가능.
- Component의
현재State값을 0으로 초기화하기
。StateUpdate함수(0)을 선언 시 0으로 초기화가 가능.import './Counter.css' import {useState} from 'react' import Counter from "./Counter2" export default function TotalCounter() { // TotalCounter 고유의 State const [totalstate,totalFunc] = useState(0); function TotalCount(num){ totalFunc(totalstate+num) } function init(){ // 현재 state값을 0으로 설정 totalFunc(0) } // 부모Component의 함수를 property로서서 자식Component 전달 return ( <> <div style={{fontSize:"100px",color:"blue"}}>{totalstate}</div> <Counter num={1} TotalCount={TotalCount}/> <Counter num={2} TotalCount={TotalCount}/> <Counter num={3} TotalCount={TotalCount}/> <button className="count" onClick={init}>init</button> </> ); };。 초기화 함수
init()을 구현 후 내부에 StateUpdate함수totalFunc(0)선언.
▶ 이후<button onClick={init}>을 통해 버튼을 누를 경우 해당 함수를 작동
prop을 통해 전달된 부모 Component의 매개변수를 포함하는 함수를JSX에서 화살표함수를 활용해 직접 호출export default function Counter({num, TotalCount}){ function increment(){ TotalCount(num) // 부모 Component State값 감소 } ; return ( <button className="countBtn" onClick={increment}>{"+"+String(num)}</button> ) }。기존 자식 Component에서는 부모 Component로부터
property로 전달된 매개변수를 포함하는 함수( =TotalCount(num))를 사용하기 위해 추가적으로 함수increment()를 구현하여 안에 포함했어야 했다.
▶ 따로 함수를 추가 구현할 필요없이JSX에서 직접 사용하기 위해서는 화살표함수를 사용.
onClick={()=>함수명(매개변수)}export default function Counter({num, TotalCount}){ return ( <button className="countBtn" onClick={()=>TotalCount(num)}>{"+"+String(num)}</button> ) }▶
JSX코드에서onClick에 직접 람다식을 통해 매개변수가 포함된 함수를 추가.export default function Counter({num, TotalCount}){ return ( <div className="Counter"> <button className="countBtn" onClick={()=>TotalCount(num)}>{"+"+String(num)}</button> <button className="countBtn" onClick={()=>TotalCount(-num)}>{"-"+String(num)}</button> </div> ) };
부모Component가{children}을 전달하고 매개변수로{ children }를 전달받는 이유?
。React Component Tree에서부모Component내부에 포함된 다른 하위Component의 Rendering을 수행하기 위한 목적.
children:React에서 Component의JSX내부에 포함된 요소를 의미하는propsconst MapComponent = ({ children }) => { return ( <div id="map" style={{ width: '100%', height: '500px' }}> {children} {/* App() Component의 <button>이 여기 렌더링됨 */} </div> ); }; const App = () => { return ( <MapComponent> <button style={{ position: 'absolute', top: 10, left: 10 }}>Zoom In</button> </MapComponent> ); };。
MapComponent의 내부에 버튼이 추가.
。MapComponent의{children}이App Component의<button>으로 설정되어 버튼이 추가됨.
▶ 원하는UI요소를children을 통해 전달 가능.
。MapComponent내부에Context객체.Provider를 활용 시 하위 Component들이Provider이Context로 전달하는 객체에 쉽게 접근 가능.const MapComponent = ({ children }) => { const [mapObj, setMapObj] = useState(null); useEffect(() => { const map = new OlMap({ target: 'map', layers: [new TileLayer({ source: new OSM() })], view: new View({ center: fromLonLat([127.0, 37.0]), zoom: 10 }), }); setMapObj(map); return () => map.setTarget(null); }, []); return ( <MapContext.Provider value={{ mapObj }}> <div id="map" style={{ width: '100%', height: '500px' }}>{children}</div> </MapContext.Provider> ); }; const Marker = () => { const { mapObj } = useContext(MapContext); useEffect(() => { if (mapObj) { const marker = new Feature(new Point(fromLonLat([127.0, 37.0]))); const vectorLayer = new VectorLayer({ source: new VectorSource({ features: [marker] }) }); mapObj.addLayer(vectorLayer); } }, [mapObj]); return null; // JSX로 아무것도 렌더링하지 않음 (맵에만 마커 추가) }; const App = () => { return ( <MapComponent> <Marker /> </MapComponent> ); };▶
Map instance가 구현 및 Context로 전달되는Component내부에서<Context.Provider>를 통해Map instance를 하위 Component로 전달 시 하위 Component에서Map instance에 접근하여Map instance를global state로서 공유 및 제어 가능.
참고
React&Openlayers연동
。npm install ol을 통해 OpenLayers Dependency를 정의import React ,{useContext} from 'react' export const MapContext = React.createContext({}); export const useMapContext = ()=>{ return useContext(MapContext) }▶
Openlayers의Map객체를Global State로서 관리하기 위한Context생성.import React, { useEffect,useState, useReducer} from 'react'; import 'ol/ol.css'; import { Map, View } from 'ol'; import { Tile } from 'ol/layer'; import { XYZ } from 'ol/source' import '../css/all4runner.css' import { MapContext } from '../Context/MapContext' import { Graticule ,Vector as VectorLayer} from 'ol/layer' const MapComponent = ({children})=>{ const [map,setMap]= useState() // state update 함수 => useReducer 적용용도 const reducer = (state,action)=>{ switch(action.type){ case "returnmap": console.log(map) return map // graticule 설정정 case "setgraticule": const gridMapLayer = new Graticule({ map:map, showLabels:true, zIndex:4 }); default: return undefined; } } // useReducer State 비동기 해결용용 const [mapstate, mapdispatch]=useReducer(reducer,undefined) // 구조분해로 받기 useEffect(() => { const Mapinstance = new Map({ target: 'map', // 하위 요소 중 id 가 map 인 element가 있어야함. layers: [ new Tile({ source : new XYZ({ url : "https://api.vworld.kr/req/wmts/1.0.0/45C98863-0CE9-39F9-881C-ED4E6DB5B3EE/Base/{z}/{y}/{x}.png" }), zIndex:0 }) ], view: new View({ projection : 'EPSG:4326', center: [127.05994054600626, 37.58400223316397], // 맵의 초기 위치 zoom: 10, // 초기 줌 레벨 }), }) setMap(Mapinstance) mapdispatch({type:"setgraticule"}) return () => Mapinstance.setTarget(undefined) }, []); return ( <MapContext.Provider value={{mapstate,mapdispatch}}> {children} </MapContext.Provider> )}; export default MapComponent;。
useState()를 활용한 비동기적State관리가 아닌,useReducer()함수를 이용해 동기적으로map객체를 Context로 전달하는 역할을 수행.
▶useState()가 비동기적으로 동작함으로 인해 발생됐던 문제들을 해결.
(ex. 자식 Component쪽에서는undefined로 전달받는다.)
▶ 본인 시도에서useEffect()등의 Hook로 비동기 문제를 해결하려고 했음에도 해결이 힘듬.
。useReducer()를 통해MapComponent에서만 사용될State를Context를 통해 하위 Component에 대해서만Global State가 작용하여 전역적으로 관리를 수행.