728x90

React 에서 네이버 지도 API 를 이용하기 위해 간단 테스트하고 적어둔다.

먼저 https://www.ncloud.com/ 사이트에서http://localhost:3000 을 추가했다.

 

 

index.html 에 라이브러리 추가

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="text/javascript" src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=키추가하세요"></script>
  </body>
</html>
 

 

인증정보에서 Client ID 값을 복사하여 붙여넣기 한다.

 

네이버맵 Sample 구현

- https://navermaps.github.io/maps.js/docs/tutorial-2-Getting-Started.html 에 지도 DOM 요소 지정하기 <div id="map" style="width:100%;height:400px;"></div> 를 포함하도록 되어 있다. return 문 안에 div 태크를 추가한다.

- 지도 띄우는 코드는 useEffect Hook을 이용하여 샘플코드를 아래와 같이 추가한다.

  샘플에 나오는 var 변수를 사용해도 되고, const, let 등으로 변경하여 변수를 사용해도 된다.

- 최상위에 const { naver } = window; 를 반드시 추가 해준다.

 

// App.js
 
import './App.css';
import NaverMapEx1 from "./NaverMapEx1";
 
function App() {
  return (
    <div className="App">
      <NaverMapEx1 />
    </div>
  );
}
 
export default App;
 
 
 
// NaverMapEx1.js
import React, {useEffect, useState} from 'react';
 
const { naver } = window;
const NaverMapEx1 = () => {
    useEffect(() => {
        const container = document.getElementById("map"); // 지도를 표시할 div
 
        // let markerList = [];
        // const HOME_PATH = window.HOME_PATH || '.';
        const position = new naver.maps.LatLng(37.3849483127.1229117);
        const mapOptions = {
            center: position,
            zoom: 17,
            minZoom: 6,
            zoomControl: true,
            zoomControlOptions: {
                position: naver.maps.Position.TOP_RIGHT,
            },
        };
 
        const map = new naver.maps.Map(container, mapOptions);
 
        const markerOptions = {
            position: position.destinationPoint(9015),
            map: map,
            icon: {
                url:'https://navermaps.github.io/maps.js/docs/img/example/ico_pin.jpg',
                //size: new naver.maps.Size(50, 52),
                origin: new naver.maps.Point(00),
                anchor: new naver.maps.Point(2526)
            }
        };
 
        const marker = new naver.maps.Marker(markerOptions);
 
        console.log("loading navermap");
    },[]);
 
    return (
        <div>
            <div id="map" style={{width:'100%', height:'800px' }}></div>
        </div>
    );
};
 
export default NaverMapEx1;
 

 

JavaScript 버전에 나온 예제대로 icon url 을 적었더니 인식이 안된다.

React 에서 이미지 경로를 어떻게 인식시키는지 알아야만 해결이 될 듯 싶다.

 

간단하게 지도 띄우는 것은 가능한데 custom marker 구현과 infowindow까지 구현해봐야 편의성을 알 수 있을 듯 싶다.

'React > React' 카테고리의 다른 글

React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

https://developers.kakao.com/ 에 접속하여 앱을 하나 생성하고 Web 사이트를 등록한다.

PC에서 구현하는 테스트 코드이므로 도메인은 http://localhost:3000 을 추가했다.

 

index.html 에 라이브러리 추가

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React 카카오맵</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%REACT_APP_KAKAO_API%&libraries=services,clusterer,drawing"></script>
  </body>
</html>
 

 

root 폴더에 .env 파일을 생성하고 아래와 같이 Key 값을 저장한다.

JavaScript 키를 복사하여 .env 파일에 붙여넣기 한다.

 

 

카카오맵 Sample 구현

- https://apis.map.kakao.com/web/guide/ 에 지도를 만들 영역 만들기 <div id="map" style="width:500px;height:400px;"></div> 를 포함하도록 되어 있다. return 문 안에 div 태크를 추가한다.

- 지도 띄우는 코드는 useEffect Hook을 이용하여 샘플코드를 아래와 같이 추가한다.

  샘플에 나오는 var 변수를 사용해도 되고, const, let 등으로 변경하여 변수를 사용해도 된다.

- 최상위에 const { kakao } = window; 를 반드시 추가 해준다.

// App.js
import './App.css';
import KakaoMapEx1 from "./KakaoMapEx1";
 
function App() {
  return (
    <div className="App">
        <KakaoMapEx1 />
    </div>
  );
}
 
export default App;
 
 
// KakaoMapEx1.js
import React, {useEffect} from 'react';
 
const { kakao } = window;
 
const KakaoMapEx1 = () => {
    useEffect(() => {
        let markers = [];
        const container = document.getElementById("map"); // 지도를 표시할 div
 
        const options = {
            center: new window.kakao.maps.LatLng(37.566826126.9786567),
            level: 12// 지도의 확대 레벨
        };
 
        const map = new window.kakao.maps.Map(container, options);
 
        const markerPosition  = new kakao.maps.LatLng(37.365264512305174127.10676860117488);
        const marker = new kakao.maps.Marker({
            position: markerPosition
        });
        marker.setMap(map);
 
        // 버튼 클릭에 따라 지도 이동 기능을 막거나 풀고 싶은 경우에는 map.setDraggable 함수를 사용
        function setDraggable(draggable) {
            // 마우스 드래그로 지도 이동 가능여부를 설정
            map.setDraggable(draggable);
        }
 
        console.log("loading kakaomap");
    }, []);
 
    return (
        <div>
            <div id="map" style={{width:'100%', height:'800px',position:'relative', overflow:'hidden' }}></div>
        </div>
    );
};
 
export default KakaoMapEx1;

 

 

'React > React' 카테고리의 다른 글

React Naver Map API 사용 샘플  (2) 2022.10.25
React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

함수형 컴포넌트는 랜더링 → component 함수 호출 모든 내부 변수 초기화의 순서를 거친다.

컴포넌트가 랜더링 될 때마다 value 라는 변수가 초기화된다.

useMemo를 사용하면 랜더링 → component 함수 호출 → Memoize 된 함수를 재사용하는 동작 순서를 거친다.

memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해 두고 동일한 입력이 들어오면 재활용하는 프로그램 기법을 말한다.

 

object는 객체 타입으로 저장될 때 참조 주소값을 저장한다.

const location = { country: isKorea ? '한국' : '미국' }; 육안으로 보면 똑같지만 객체 타입으로 메모리에 저장될 때의 주소는 완전히 달라서 useMemo 를 사용하지 않으면 계속 rendering 될 수 있다.

React rerendering 하는 조건
- props가 변경되었을 때
- state가 변경되었을 때
- 부모 컴포넌트가 rendering 되었을 때
- forceUpdate() 를 실행하였을 때

useEffect, useCallback, useMemo의 모든 종속성은 참조 동일성을 확인한다.
useEffect() 함수는 두 번째 인자로 넘어온 의존 배열이 변경될 때만 첫 번째 인자로 넘어온 함수를 호출한다.

import React, {useEffect, useMemo, useState} from 'react';
 
const UseMemoEx = () => {
    const [number, setNumber] = useState(0);
    const [isKorea, setIsKorea] = useState(true);
 
    const location = useMemo(() => {
        return {
            country: isKorea ? '한국' : '미국'
        }
    }, [isKorea]);
 
    useEffect(() => {
        console.log('useEffect... 호출');
    }, [location]);
 
    return (
        <div>
            <h3>하루에 몇 끼 먹어요?</h3>
            <input
                type="number"
                value={number}
                onChange={(e) => setNumber(e.target.value)}
            />
            <p> 하루 식사 횟수 : {number}</p>
 
            <h3>어느 나라에 있어요?</h3>
            <p>나라: {location.country}</p>
            <button onClick={() => setIsKorea(!isKorea)}>토글</button>
        </div>
    );
};
 
export default UseMemoEx;

 

자식 컴포넌트에서 useEffect가 반복적으로 트리거되는 것을 막고 싶을 때 사용하자.

 

useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.

The useCallback and useMemo Hooks are similar. 

The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

The React useCallback Hook returns a memoized callback function.
The useCallback Hook only runs when one of its dependencies update.

useCallback(fn, deps)
의존성 배열인 deps에 변경을 감지해야할 값을 넣어주게 되면 deps가 변경될 때마다 콜백 함수를 새로 생성한다.

 

 

let x = 3;
let y = 4;
 
// 자바스크립트에서 함수는 객체로 취급한다.
const add1 = (x, y) => x + y;
const add2 = (x, y) => x + y;
 
console.log(add1(x,y)); // 결과 7
console.log(add2(x,y)); // 결과 7
console.log(add1 === add2); // 참조변수 비교 결과 : false

 

 

 
import React, {useCallback, useState} from 'react';
 
function Light({ room, on, toggle }) {
    console.log({ room, on });
    return (
        <button onClick={toggle}>
            {room} {on ? "💡" : "⬛"}
        </button>
    );
}
 
Light = React.memo(Light);
 
const UseCallbackEx = () => {
    const [bedroom, setBedroom] = useState(false);
    const [kitchen, setKitchen] = useState(false);
    const [bath, setBath] = useState(false);
 
    const toggleBedroom = useCallback(() =>
        setBedroom(!bedroom), [bedroom]
    );
    const toggleKitchen = useCallback(() =>
        setKitchen(!kitchen), [kitchen]
    );
    const toggleBath = useCallback(() =>
        setBath(!bath), [bath]
    );
 
    return (
        <div>
            <Light room="주방" on={kitchen} toggle={toggleKitchen} />
            <Light room="욕실" on={bath} toggle={toggleBath} />
            <Light room="침실" on={bedroom} toggle={toggleBedroom} />
        </div>
    );
};
 
export default UseCallbackEx;

참조 : https://www.daleseo.com/react-hooks-use-callback/

 

React Hooks: useCallback 사용법

Engineering Blog by Dale Seo

www.daleseo.com

 

 

 

'React > React' 카테고리의 다른 글

React Naver Map API 사용 샘플  (2) 2022.10.25
React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
블로그 이미지

Link2Me

,
728x90

import React, {useRef, useState} from 'react';
 
const UseRef = () => {
    const [renderer, setRenderer] = useState(0); // 숫자 증가시 화면 랜더링 발생
    const countRef = useRef(0); // 숫자 증가해도 화면 랜더링 없음
    let countVar = 0// 화면 랜더링 발생하면 값 초기화 발생
 
    const doRendering = () => {
        setRenderer(renderer + 1);
    }
 
    const increaseRef = () => {
        countRef.current = countRef.current + 1;
        console.log('ref:', countRef.current);
    }
 
    const increaseVar = () => {
        countVar = countVar + 1;
        console.log('var:', countVar);
    };
 
    return (
        <div>
            <p>Ref: {countRef.current}</p>
            <p>Var: {countVar}</p>
            <button onClick={doRendering}>랜더 UP</button>
            <button onClick={increaseRef}>Ref UP</button>
            <button onClick={increaseVar}>Var UP</button>
        </div>
    );
};
 
export default UseRef;

 

import logo from './logo.svg';
import './App.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import useWindowWidth from "./hooks/useWindowWidth";
import UseRef from "./components/UseRef";
 
function App() {
    const width = useWindowWidth();
    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <UseRef />
                {width}
            </header>
        </div>
    );
}
 
export default App;

 

 

useEffect 와 useState를 잘못 사용하면 무한 랜더링이 발생할 수 있다.

useRef를 useEffect 와 사용하면 문제가 해결될 수 있으니 알아두자.

 

 

import React, {useRef, useState} from 'react';
 
const UseRefInput = () => {
    const [inputValue, setInputValue] = useState('');
    const useridInput = useRef();
 
    const onRest = () => {
        setInputValue('');
        useridInput.current.focus();
    };
 
    return (
        <div>
            <input type="text" name="userId"
                   ref={useridInput}
                   onChange={(e)=> setInputValue(e.target.value)}
                   placeholder="userID 입력"
                   value={inputValue} />
            <button onClick={onRest}>초기화</button>
            <p>input: {inputValue}</p>
        </div>
    );
};
 
export default UseRefInput;

 

 

'React > React' 카테고리의 다른 글

React 카카오맵 API 사용 샘플  (0) 2022.10.24
React useMemo & useCallback  (0) 2022.10.24
React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
React CORS error 해결 방법  (0) 2022.08.20
블로그 이미지

Link2Me

,

React useReducer

React/React 2022. 10. 13. 23:47
728x90

 

  • state : 현재 상태
  • dispatch : action을 발생시키는 함수
  • reducer : state와 action를 받아 새로운 state를 반환하는 함수
  • initialState : 초기값

 

useReducer 함수에는 첫번째 인자로 reducer 함수를, 두번째 인자로 초기 상태값을 넣어준다.

import React, { useReducer } from 'react';
 
function reducer(state, action) {
    switch (action.type) {
        case 'PLUS':
            return state + 1;
        case 'MINUS':
            return state - 1;
        default:
            return state;
    }
}
 
function Counter() {
    const [number, dispatch] = useReducer(reducer, 0);
 
    const onIncrease = () => {
        dispatch({ type: 'PLUS' });
    };
 
    const onDecrease = () => {
        dispatch({ type: 'MINUS' });
    };
 
    return (
        <div>
            <h1>{number}</h1>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    );
}
 
export default Counter;

 

import logo from './logo.svg';
import './App.css';
import Counter from "./counter";
 
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Counter />
      </header>
    </div>
  );
}
 
export default App;
 

 

 

 

'React > React' 카테고리의 다른 글

React useMemo & useCallback  (0) 2022.10.24
React useRef 사용 예제  (0) 2022.10.15
React-bootstrap Header.js 테스트  (0) 2022.08.21
React CORS error 해결 방법  (0) 2022.08.20
React Query String  (0) 2022.06.08
블로그 이미지

Link2Me

,
728x90

https://react-bootstrap.github.io/getting-started/introduction/

 

React-Bootstrap

The most popular front-end framework, rebuilt for React.

react-bootstrap.github.io

에 설명된 것처럼

npm install react-bootstrap bootstrap

으로 모듈을 추가하고, App.js 또는 index.js 에

import 'bootstrap/dist/css/bootstrap.min.css';

를 추가한다.

 

Header.js 파일을 아래와 같이 하고 테스를 했더니 PC화면 사이즈에서는 속도 문제는 없다.

Navbar.Offcanvas 기능이 활성화되는 스마트폰 크기로 되었을 때 Menu 반응속도가 너무 느리다.

import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Form from 'react-bootstrap/Form';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import Offcanvas from 'react-bootstrap/Offcanvas';
 
const Header = () => {
    return (
        <>
            <Navbar bg="primary" expand='sm' className="mb-3">
                <Container fluid>
                    <Navbar.Brand href="/">Navbar</Navbar.Brand>
                    <Navbar.Toggle aria-controls='navbar-expand-sm'/>
                    <Navbar.Offcanvas id='navbar-expand-sm' aria-labelledby='navbar-expand-sm' placement="end">
                        <Offcanvas.Header closeButton>
                            <Offcanvas.Title id='navbarLabel-expand-sm'>
                                홍길동
                            </Offcanvas.Title>
                        </Offcanvas.Header>
                        <Offcanvas.Body>
                            <Nav className="justify-content-end flex-grow-1 pe-3">
                                <Nav.Link href="/">Home</Nav.Link>
                                <Nav.Link href="/login">Login</Nav.Link>
                                <Nav.Link href="/register">Sign Up</Nav.Link>
                                <NavDropdown title="Dropdown" id='navbarDropdown-expand-sm'>
                                    <NavDropdown.Item href="/login">로그인</NavDropdown.Item>
                                    <NavDropdown.Item href="/register">회원가입</NavDropdown.Item>
                                    <NavDropdown.Divider/>
                                    <NavDropdown.Item href="#action5">
                                        Something else here
                                    </NavDropdown.Item>
                                </NavDropdown>
                            </Nav>
                        </Offcanvas.Body>
                    </Navbar.Offcanvas>
                </Container>
            </Navbar>
        </>
    )
}
 
export default Header;

 

Navbar.Offcanva 기능이 없는 단순 형태 구성 코드는 속도 문제 없었다.

import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
 
const Header = () => {
    return (
        <>
            <Navbar bg="primary" variant="dark">
                <Container fluid>
                    <Navbar.Brand href="/">Navbar</Navbar.Brand>
                    <Navbar.Toggle aria-controls="responsive-navbar-nav"/>
                    <Navbar.Collapse id="responsive-navbar-nav">
                        <Nav className="me-auto">
                            <Nav.Link href="/">Home</Nav.Link>
                            <Nav.Link href="/register">Register</Nav.Link>
                            <Nav.Link href="/login">Login</Nav.Link>
                        </Nav>
                    </Navbar.Collapse>
                </Container>
            </Navbar>
        </>
    )
}
 
export default Header;

Layout 구성하는 것에 대해서 좀 더 다양한 테스트를 해봐야 알 수 있을 듯 싶다.

 

'React > React' 카테고리의 다른 글

React useRef 사용 예제  (0) 2022.10.15
React useReducer  (0) 2022.10.13
React CORS error 해결 방법  (0) 2022.08.20
React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
블로그 이미지

Link2Me

,
728x90

React (Front-End) 와 PHP (Back-End) 간에 통신하는 기능으로 유투브 동영상을 시청하면서 타이밍해가면서 동작 여부를 확인하는데 안된다.

 

윈도우에서 React 를 설치하고, 윈도우에 AutoSet10 을 설치하고 http://localhost/php-react/insert.php 로 데이터 전송을 시도하면 같은 localhost 로 인식하여 MySQL DB에 데이터가 잘 저장된다.

 

윈도우에 CentOS 7.9 를 VirtualBox 를 이용하여 설치하고, Node.js 와 React 를 설치하고 PHP 도 같이 설치했다.

IPTIME 공유기 환경에서 http://192.168.1.20:3000 번으로 react 개발자 모드로 접속하고,

http://192.168.1.20/php-react/insert.php 로 접속을 했더니 에러가 발생한다.

 

80 포트와 3000번 포트가 서로 달라서 생기는 문제다.

일반적으로 브라우저는 보안 문제로 인해 동일 출처 정책(SOP, Same Origin Policy)을 따른다.

URL의 프로토콜, 호스트, 포트가 모두 같아야 동일한 출처로 볼 수 있는데, 예를 들어 abc.com 호스트에게 받은 페이지에서 cde.com 호스트로 데이터를 요청할 수 없다. 출처가 다른 호스트로 데이터를 요청하는 경우 CORS 정책을 위반하게 된다. 

 

Register.js 파일 내용

 

insert.php 파일 내용

 

문제 해결 방법

1. package.json  파일에 추가할 사항

 

2. Register.js 파일 수정사항

http://192.168.1.20 remove

3. Chrome Broswer 결과 확인

4. DB 테이블 확인

테이블에 저장이 잘 된 것을 확인할 수 있다.

 

 

 

 

 

 

'React > React' 카테고리의 다른 글

React useReducer  (0) 2022.10.13
React-bootstrap Header.js 테스트  (0) 2022.08.21
React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
React useState  (0) 2022.06.04
블로그 이미지

Link2Me

,

React Query String

React/React 2022. 6. 8. 00:05
728x90

http://localhost:3000/about?name=react&id=123 와 같은 URL 입력값에서 Query String을 추출하는 함수 예제이다.

React 강의를 듣고 그대로 타이핑을 하는데 동작이 안된다. 오래된 버전이라 그런가???

구글링을 해보고 그대로 실행해보는데도 역시 안되는 것들이 있다.

react-router-dom v6 에 맞게 구현해야 동작된다.

import React, {useState} from 'react';
import { useLocation } from 'react-router';
import qs from "query-string";  // npm install query-string
 
 
const About = () => {
    // In React Hooks:
    const searchParams = useLocation().search;
    console.log(searchParams);
    const query = qs.parse(searchParams);
    console.log(query);
 
    const name = new URLSearchParams(searchParams).get('name');
    const id = new URLSearchParams(searchParams).get('id');
    console.log({ name, id });
 
    return (
        <div>
            <h2>About 페이지입니다.</h2>
            {query.name && <p>name 은 {query.name} 입니다.</p>}
        </div>
    );
};
 
// https://everttimberg.io/blog/custom-react-hook-query-state/ 참고하자.
 
export default About;

 

비구조화 할당 문법을 통해 props 내부 값 추출하기

import {Route, Routes, useParams} from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import About from "./pages/About";
 
function App() {
    const { id } = useParams();
    return (
        <Routes>
            <Route path="/" element={<Home />}/>
            <Route path="/profile" element={<Profile/>}/>
            <Route path="/profile/:id" element={<Profile/>}/>
            <Route path="/about" element={<About name={"React"/>}/>
        </Routes>
    );
}
 
export default App;

 

props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며,

컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다.

{props.name} 대신에 {name} 으로 내부 값을 바로 추출하는 방법 : const { name } = props;

import React, {useState} from 'react';
import { useLocation } from 'react-router';
import qs from "query-string";  // npm install query-string
 
 
const About = props => {
    // In React Hooks:
    const searchParams = useLocation().search;
    console.log(searchParams);
    const query = qs.parse(searchParams);
    console.log(query);
 
    //const name = new URLSearchParams(searchParams).get('name');
    //const id = new URLSearchParams(searchParams).get('id');
    //console.log({ name, id });
 
    const { name } = props; // 비구조화 할당 문법
 
    return (
        <div>
            <h2>{name} About 페이지입니다.</h2>
            {query.name && <p>name 은 {query.name} 입니다.</p>}
        </div>
    );
};
 
 
export default About;

리액트에는 두가지 종류의 state가 있다.

하나는 클래스형 컴포넌트가 지니고 있는 state 이고,

다른 하나는 함수 컴포넌트에서 useState라는 함수를 통해 사용하는 state이다.

 

 

'React > React' 카테고리의 다른 글

React-bootstrap Header.js 테스트  (0) 2022.08.21
React CORS error 해결 방법  (0) 2022.08.20
React Router v6  (0) 2022.06.07
React useState  (0) 2022.06.04
React 값 전달(부모 → 자식, 자식 → 부모)  (0) 2022.06.03
블로그 이미지

Link2Me

,

React Router v6

React/React 2022. 6. 7. 06:34
728x90

웹 애플리케이션에서 라우팅이라는 개념은 사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것을 의미한다.

react-router-dom 버전 6 에서는 element 로 컴포넌트를 만들어야 동작하고, component 로 된 것은 에러 발생하고 동작되지 않는다.

V6 에서는 Switch 가 사라지고, Routes 로 대체되었다. 

Routes는 기존 Switch 처럼 경로 순서를 기준으로 선택하는 것이 아닌, 가장 일치하는 route 기반으로 선택하게 된다.

useHistory 가 사라지고, useNavigate 로 대체되었다.

- useNavigate로 기존에 useHistory의 기능을 전부 대체 가능하다.
- useHistory의 history는 객체였지만 useNavigate의 navigate는 함수다.
Route에 children, component가 사라지고, element 사용한다.

 

npm install react-router-dom // 라이브러리 설치

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom";
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
 
reportWebVitals();

 

Route에 exact Prop 사라졌다. exact가 기본으로 되어있다.

기존 Route는 꼭 Switch 가 상위 요소로 없어도 되지만, v6의 Route는 Routes의 직속 자식이어야 한다.

import {Route, Routes, useParams} from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import About from "./pages/About";
 
function App() {
    const { id } = useParams();
    return (
        <Routes>
            <Route exact={true} path="/" element={<Home />}/>
            <Route path="/profile" element={<Profile/>}/>
            <Route path="/profile/:id" element={<Profile/>}/>
            <Route path="/about" element={<About/>}/>
        </Routes>
    );
}
 
export default App;

 

Link 는 컴포넌트, to 는 props

import React from 'react';
import {Link} from "react-router-dom";
 
const Home = () => {
    return (
        <div>
            <h1>Home 페이지입니다.</h1>
            <Link to={"/about?name=react"}>소개</Link>
        </div>
    );
};
 
export default Home;

 

Profile = (props) => 를 사용하지 말라.

http://localhost:3000/profile/4 를 해보면 결과를 확인할 수 있다.

import React from 'react';
import {useParams} from "react-router-dom";
 
const Profile = () => {
    // react-router-dom 버전 6부터는 element로 컴포넌트를 만들고
    // route props(match, history, location)을 받지 않는다.
    // useParams, useLocation, useHistory를 사용하여 route context에 접근한다.
    // let id = props.match.params.id 를 사용하면 에러 발생한다.
    const { id } = useParams();
    return (
        <div>
            <h1>Profile 페이지입니다.</h1>
            {id && <h3>ID: {id}</h3>}
        </div>
    );
};
 
export default Profile;

 

Query String 에 대한 사항은 다음 게시글을 읽어보면 된다.

https://link2me.tistory.com/2177

 

 

 

'React > React' 카테고리의 다른 글

React CORS error 해결 방법  (0) 2022.08.20
React Query String  (0) 2022.06.08
React useState  (0) 2022.06.04
React 값 전달(부모 → 자식, 자식 → 부모)  (0) 2022.06.03
React Event 처리하기  (0) 2022.05.29
블로그 이미지

Link2Me

,

React useState

React/React 2022. 6. 4. 00:05
728x90

Hook은 React 버전 16.8(2019년)부터 React 요소로 새로 추가되었다.

https://ko.reactjs.org/docs/hooks-effect.html 가 React 에서 기본 제공하는 내용 설명이다.

함수형 컴포넌트의 주요 단점은 state 와 라이프사이클 API 의 사용이 불가능하다는 점이었는데, 리액트 16.8 업데이트 이후 Hooks 기능이 도입되면서 해결되었다.

현재 리액트 공식 매뉴얼에서는, Class형 컴포넌트보다는 Function형 컴포넌트와 Hooks로 React 프로젝트를 만들기를 권장하고 있다.

 

App.js

import logo from './logo.svg';
import './App.css';
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
import Example3 from "./components/Example3";
 
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Example1 />
        <Example2 />
        <Example3 />
      </header>
    </div>
  );
}
 
export default App;

 

Example1.jsx

파일명을 생성하고 파일 안에서 rcc 를 입력하고 TAB 키를 누르면 자동완성된 기본 컴포넌트가 만들어진다.

클래스형 컴포넌트에서는 render함수가 꼭 있어야 한다.

import React, {Component} from 'react';
 
class Example1 extends Component {
    state = {count: 0};
 
    render() {
        const { count } = this.state;
        return (
            <div>
                <p>You clicked {count} times.</p>
                <button onClick={this.click}>Click me</button>
            </div>
        );
    }
 
    click = () => {
        this.setState({
            count: this.state.count + 1
        });
    };
}
 
export default Example1;

 

Example2.jsx

- useState 함수의 인자에는 상태의 초기값을 넣어 준다. 초기값은 숫자, 문자열, 객체, 배열 등

- 배열 비구조화 할당 const [count, setCount] 에서 첫번째 원소는 현재 상태이고, 두번째 원소는 상태를 바꾸어주는 함수이다. 이 함수를 Setter 함수라고 부른다.

- 하나의 useState 함수는 하나의 상태 값만 관리할 수 있다.

  컴포넌트에서 관리해야 할 상태가 여러 개라면 useState를 여러 번 사용하면 된다.

- state 는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트할 수 있다.

import React from 'react';
 
const Example2 = () => {
    const [count, setCount] = React.useState(0);
 
    function click() {
        setCount(count + 1);
    }
 
    return (
        <div>
            <p>You clicked {count} times.</p>
            <button onClick={click}>Click me</button>
        </div>
    );
};
 
export default Example2;

 

Exampe3.jsx

// rsc 입력하고 Tab 키를 누른다.
import React from 'react';
 
const Example3 = () => {
    // useState : state를 대체할 수 있다.
    const [state, setState] = React.useState({count: 0});
 
    function click() {
        setState((state) => ({
            count: state.count + 1,
        }));
    }
 
    return (
        <div>
            <p>You clicked {state.count} times.</p>
            <button onClick={click}>Click me</button>
        </div>
    );
};
 
export default Example3;

 

 

이제 bootstrap4 를 적용해보자.

# Step1 – Install Bootstrap 4
npm install bootstrap --save

 

App.js

import logo from './logo.svg';
import './App.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
import Example3 from "./components/Example3";
 
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Example1 />
        <Example2 />
        <Example3 />
      </header>
    </div>
  );
}
 
export default App;

 

 

Exampl1.jsx

import React, {Component} from 'react';
 
class Example1 extends Component {
    state = {count: 0};
 
    render() {
        const { count } = this.state;
        return (
            <div className="col-md-12 text-center">
                <p>You clicked {count} times.</p>
                <button className="btn btn-primary" onClick={this.click}>Click me</button>
            </div>
        );
    }
 
    click = () => {
        this.setState({
            count: this.state.count + 1
        });
    };
}
 
export default Example1;

 

 

 

'React > React' 카테고리의 다른 글

React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
React 값 전달(부모 → 자식, 자식 → 부모)  (0) 2022.06.03
React Event 처리하기  (0) 2022.05.29
React Component 만들기  (0) 2022.05.28
블로그 이미지

Link2Me

,
728x90

React Component 에서 값을 전달하는 방법이다.

자식 → 부모 데이터 전달

props : 상위 컴포넌트에서 하위 컴포넌트로 값을 전달하는 수단

- 하위 컴포넌트에서 상위 컴포넌트로 값을 전달할 수 없다.

- 하위 컴포넌트에서 상위 컴포넌트가 전달해준 값에 접근할 수 있게 해준다.

 

const [스테이트 값, 스테이트 변경 함수] = useState(스테이트 초기값);

import React, {useState} from 'react';
import Child from "./Child";
 
const Parent = () => {
    const [data, setData] = useState(0);
    // 1. 부모 컴포넌트에서 useState 를 통해 전달받은 데이터를 저장할 변수를 선언한다.
    // 2. 부모 컴포넌트에서 props로 함수를 넣어주면,
    //    자식 컴포넌트에서 그 함수를 이용해 값을 전달한다.
 
    const parentFnc = (data) => {
      setData(data);
    }
 
    return (
        <div>
            <div>부모 컴포넌트 값 : {data}</div>
            <Child number={data} getData={parentFnc} />
        </div>
    );
};
 
export default Parent;

 

Child 컴포넌트

Event Handling

- camelCase 로만 사용할 수 있다. onClick, onMouseEnter

- 이벤트에 연결된 자바스크립트 코드는 함수이다. onClick={함수}

- 실제 DOM 요소들에만 사용 가능하다.

import React from 'react';
 
const Child = props => {
    const onClick = () => {
      console.log(props.number);
      props.getData(props.number + 1);
    }
 
    return (
        <div>
            <button onClick={onClick}>+자식버튼</button>
        </div>
    );
};
 
export default Child;

Child 컴포넌트를 아래와 같이 수정 가능하다.

import React from 'react';
 
const Child = props => {
    const {number, getData} = props; // 비구조화 할당 문법
 
    const onClick = () => {
        console.log(number);
        getData(number + 1);
    };
 
    return (
        <div>
            <button onClick={onClick}>+자식버튼</button>
        </div>
    );
};
 
export default Child;

 

import Parent from "./components/Parent";
 
function App() {
  return (
    <div className="App">
      <Parent />
    </div>
  );
}
 
export default App;

 

부모 → 자식 데이터 전달

 

 

 

 

 

 

 

'React > React' 카테고리의 다른 글

React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
React useState  (0) 2022.06.04
React Event 처리하기  (0) 2022.05.29
React Component 만들기  (0) 2022.05.28
블로그 이미지

Link2Me

,
728x90

React 엘리먼트에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리 방식과 매우 유사하다.
- React의 이벤트는 소문자 대신 캐멀 케이스(camelCase)를 사용한다.
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달한다.

- DOM 요소에만 이벤트 설정이 가능하다. div, button, input, form, ul, li, span 등

- React Component 에는 이벤트 설정이 불가능하다.

 

Event Handler 예제

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <title>React App Sample</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
    class Component extends React.Component {
        constructor(props) {
            super(props);
            this.state = {count: 0};
            this.click = this.click.bind(this);
        }
 
        render() {
            return (
                <div>
                    <h3>{this.props.item}</h3>
                    <p>{this.state.count}</p>
                    <button onClick={this.click}>클릭</button>
                </div>
            );
        }
 
        click() {
            console.log("clicked");
            this.setState((state) => ({
                ...state,
                count: state.count + 1,
            }));
        }
    }
 
    // 사용
    ReactDOM.render(
        <Component item={"Front-End : React"}/>,
        document.querySelector('#root')
    );
</script>
</body>
</html>

 

여기에 버튼의 명칭이 ON, OFF 가 번갈아 가면서 나오도록 하는 걸 추가해보자.

<script type="text/babel">
    class Component extends React.Component {
        constructor(props) {
            super(props);
            this.state = {count: 0, isToggleOn: true};
            this.click = this.click.bind(this);
        }
 
        click() {
            console.log("clicked");
            this.setState((state) => ({
                ...state,
                count: state.count + 1,
                isToggleOn: !state.isToggleOn
            }));
        }
 
        render() {
            return (
                <div>
                    <h3>{this.props.item}</h3>
                    <p>{this.state.count}</p>
                    <button onClick={this.click}>{this.state.isToggleOn ? 'ON' : 'OFF'}</button>
                </div>
            );
        }
 
    }
 
    // 사용
    ReactDOM.render(
        <Component item={"React Event Handler"}/>,
        document.getElementById('root')
    );
</script>

 

 

 

 

 

 

 

 

'React > React' 카테고리의 다른 글

React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
React useState  (0) 2022.06.04
React 값 전달(부모 → 자식, 자식 → 부모)  (0) 2022.06.03
React Component 만들기  (0) 2022.05.28
블로그 이미지

Link2Me

,
728x90

https://ko.reactjs.org/docs/react-component.html 에 기본적인 React Component 사항을 확인한다.

 

 

컴포넌트는 소프트웨어의 재사용성을 높이고 유지보수를 용이하게 하기 위해 나온 기술이다.

컴포넌트는 두 가지 인스턴스 속성으로 props와 state를 가지고 있다.

props는 부모 컴포넌트가 자식 컴포넌트에게 주는 값이다.
어떠한 값을 컴포넌트에 전달해 줘야 할때 사용하며 할당된 후 컴포넌트 내부에서 값을 변경할 수 없다.
state는 컴포넌트 내부에서 선언하며 내부에서 값을 변경할 수 있다. 동적인 데이터를 다룰 땐 state를 사용한다.

둘(props, state)다 변경이 되면, render 가 다시 일어날 수 있다.

 

Class Component 예제1

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>React App Sample</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
  //console.log(React);
  //console.log(ReactDOM);
 
  // 리액트 컴포넌트는 리엑트로 만들어진 앱을 이루는 최소한의 단위
  // 컴포넌트는 데이터(props)를 입력받아 View(state) 상태에 따라 DOM Node를 출력하는 함수
  // 컴포넌트 이름은 항상 대문자로 시작해야 한다. 
// 소문자로 시작하는 컴포넌트는 DOM 태그로 취급하기 때문이다.
 
  // Class Component 정의
  class ClassComponent extends React.Component {
      // render() 메서드는 클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메서드
      render() {
          return <div>Hello React world.</div>;
      }
  }
 
  // 사용
  ReactDOM.render(
      <ClassComponent />,
      document.querySelector('#root')
  );
</script>
</body>
</html>

 

Function Component 예제1

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>React App Sample</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
  // 컴포넌트 이름은 항상 대문자로 시작해야 한다. 
// 소문자로 시작하는 컴포넌트는 DOM 태그로 취급하기 때문이다.
 
  // Function Component 정의
  function FunctionComponent() {
      return <div>Hello, React world.</div>;
  }
 
  // 화살표 함수 컴포넌트 정의
 const FunctionComponent2 = () => <div>Hello, React world.</div>;
 
  // 사용
  ReactDOM.render(
      <FunctionComponent />,
      document.querySelector('#root')
  );
</script>
</body>
</html>

 

React createElement 로 컴포넌트 만들기 예제

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>React App Sample</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
  // 컴포넌트 이름은 항상 대문자로 시작해야 한다. 
  // 소문자로 시작하는 컴포넌트는 DOM 태그로 취급하기 때문이다.
 
  const Component = () => {
    return React.createElement('p'null, `type 이 "React 컴포넌트" 입니다.`);
    // React.createElement(태그, props, childeren)
  }
 
  // 사용
  ReactDOM.render(
      React.createElement(Component, nullnull),
      document.querySelector("#root")
  );
</script>
</body>
</html>

 

위 예제는 태그가 여러개 일 경우 처리하는데 상당히 어렵다.

https://babeljs.io/ 사이트에서 직접 입력해보면...

자동으로 React.createElement 를 생성해주는 걸 확인할 수 있다.

 

React 에서 사용하는 JSX 문법

- 최상위 요소가 하나여야 한다.

- 자식들을 바로 랜더링하고 싶으면, <>자식들</>를 사용한다.

- 자바스크립트 표현식을 사용하려면 {표현식}을 이용한다.

- if 문을 사용할 수 없기 때문에 삼항연산자 혹은 &&를 사용한다.

- style을 이용해 인라인 스타일링이 가능하다.

- class 대신 className을 사용해 class를 적용할 수 있다.

- 자식요소는 엄격하게 쌍으로 닫아야 하고, 자식요소가 없다면 열면서 닫아야 한다. <br />

 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>React App Sample</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
  // 사용
  ReactDOM.render(
      <div>
          <div>
              <h2>Front-end Frameworks</h2>
              <ul>
                  <li>React</li>
                  <li>Angular</li>
                  <li>Vue.js</li>
              </ul>
          </div>
      </div>,
      document.querySelector("#root")
  );
</script>
</body>
</html>

 

함수형 컴포넌트로 만들어서 바꾸면

<script type="text/babel">
  function Component() {
      return (
          <div>
              <div>
                  <h2>Front-end Frameworks</h2>
                  <ul>
                      <li>React</li>
                      <li>Angular</li>
                      <li>Vue.js</li>
                  </ul>
              </div>
          </div>
      )
  }
 
  // 사용
  ReactDOM.render(
      <Component />,
      document.querySelector("#root")
  );
</script>

 

이제 값을 전달하는 컴포넌트를 구현하는 간단 예제이다.

<script type="text/babel">
  function Component(props) {
      return (
          <div>
              <div>
                  <h2>Front-end Frameworks</h2>
                  <ul>
                      <li>{props.item}</li>
                      <li>Angular</li>
                      <li>Vue.js</li>
                  </ul>
              </div>
          </div>
      )
  }
 
  // 사용
  ReactDOM.render(
      <Component item="리액트" />,
      document.querySelector("#root")
  );
</script>

 

class 컴포넌트 값 전달 예제

전달하는 값이 없으면 기본으로 지정된 값이 보이는 걸 확인할 수 있다.

<Component item="React" />  라고 값을 지정하면 지정된 값이 출력되는 걸 확인할 수 있다.

<script type="text/babel">
    class Component extends React.Component {
        render(){
            return (
                <div>
                    <div>
                        <ul>
                            <li>{this.props.item}</li>
                        </ul>
                    </div>
                </div>
            )
        }
 
        static defaultProps = {
            item : "Vue.js"
        };
    }
 
    // 사용
    ReactDOM.render(
        <Component />,
        document.querySelector('#root')
    );
</script>

 

state

<script type="text/babel">
    class Component extends React.Component {
        // state = {
        //     count: 0,
        // }
 
        constructor(props) {
            super(props);
            this.state = { count: 0}
        }
 
        render() {
            return (
                <div>
                    <ul>
                        <li>{this.props.item}</li>
                        <li>{this.state.count}</li>
                    </ul>
                </div>
            );
        }
 
        componentDidMount() {
            setTimeout(() => {
                this.setState({
                    count: this.state.count + 1,
                });
            }, 1000);
        }
 
        static defaultProps = {
            item: "React"
        };
    }
 
    // 사용
    ReactDOM.render(
        <Component/>,
        document.querySelector('#root')
    );
</script>

 

componentDidMount 처리를 다르게 하는 법

<script type="text/babel">
    class Component extends React.Component {
        constructor(props) {
            super(props);
            this.state = { count: 0}
        }
 
        render() {
            return (
                <div>
                    <ul>
                        <li>{this.props.item}</li>
                        <li>{this.state.count}</li>
                    </ul>
                </div>
            );
        }
 
        componentDidMount() {
            setTimeout(() => {
                this.setState((previousState)=>{
                    const newState = { count: previousState.count + 1}
                    return newState;
                });
            }, 1000);
        }
 
        static defaultProps = {
            item: "React"
        };
    }
 
    // 사용
    ReactDOM.render(
        <Component item={"Front-End : React"/>,
        document.querySelector('#root')
    );
</script>

 

 

 

 

 

'React > React' 카테고리의 다른 글

React Query String  (0) 2022.06.08
React Router v6  (0) 2022.06.07
React useState  (0) 2022.06.04
React 값 전달(부모 → 자식, 자식 → 부모)  (0) 2022.06.03
React Event 처리하기  (0) 2022.05.29
블로그 이미지

Link2Me

,