본문 바로가기

코딩

[LG CNS AM CAMP 1기] AM(Application Modernization)5일차(12/30)

 

블로그란 -> 내가 하는 것을 다른 사람에게 알리는 것!

 

 


 

지난주 -> 자바 스크립트, 하드 코딩된 데이터를 활용

그러나 실제로는 DB에 저장되어 있고, 데이터가 변경됨 -> 프론트엔드에 보여주어야 함

restapi가 제공해주는 것을 보여줌

HTTP 프로토콜을 이용해서 데이터를 요청, 그 데이터를 활용하기 좋게 바꿈

 

최근에 많이 쓰는 것 : 엑시오스

 

1교시

  1. JSON Formatter
  2. axios
  3. get 요청 방식
  4. post 요청 방식
  5. 요청 선행 처리
  6. 응답 선행 처리

 

 

 

 


JSON Formatter 

 

좌 json

 

2. axios

자바 스크립트 환경에서 HTTP요청을 보내고, 응답을 처리하는데 사용되는 promise 기반의 HTTP 클라이언트 라이브러리

요청 데이터를 JSON으로 직렬화하거나, 응답 데이터를 JSON으로 자동 파싱

간단한 사용법과 강력한 기능을 제공하여 RESTful  API와의 상호작용하여 널리 활용

 

응답 데이터 : 문자열 

사용법이 쉬움

 

 

사용 예시)

 

 

2. GET 요청

주소만 넘김

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--axios 라이브러리 추가-->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <!--가져오고 싶은 데이터-->
    <script>
        axios.get("https://jsonplaceholder.typicode.com/posts")
        .then(res =>{
					성공 처리 구문
        })
        .catch(err =>{
            
            실패 처리 구문
        })
    </script>
</head>
<body>
   
</body>
</html>

 

ex)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--axios 라이브러리 추가-->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <!--가져오고 싶은 데이터-->
    <script>
        axios.get("https://jsonplaceholder.typicode.com/posts")
        .then(res =>{ 
        <!--가져온 데이터 log 찍기-->
            console.log(res.data); 
        })
        <!--가져오지 못한 데이터 오류 발생 -->
        .catch(err =>{
            console.log(err);
        })
    </script>
</head>
<body>
   
</body>
</html>

 

 

결과창

 

2-3) Title만 출력하고 싶은 경우 -> JSON의 특정 데이터만 출력하고 싶은 경우 

 

1) forEach

 res.data.forEach(d => console.log(d.title));

 

2) map

res.data.map(d =>console.log(d.title));

 

 

3)전체 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--axios 라이브러리 추가-->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <!--가져오고 싶은 데이터-->
    <script>
        axios.get("https://jsonplaceholder.typicode.com/posts")
        .then(res =>{
            console.log(res.data);//데이터 로그 찍기
            //만약 Title콘솔로 찍고 싶다면 -> 데이터는 배열로 가지고 오게 됨 -> 
            res.data.forEach(d => console.log(d.title));
            console.log("-------------------------")
            res.data.map(d =>console.log(d.title));
        })
        .catch(err =>{
            console.log(err); //오류 찍기
        })
    </script>
</head>
<body>
   
</body>
</html>

 

3) POST 요청 방식

서버로 전달하는 내용이 요청 본문에 존재해야 함.  (요청 파라미터)

 

결과 

 

post 요청 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--axios 라이브러리 추가-->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <!--가져오고 싶은 데이터-->
    <script>
        axios
        .post("https://jsonplaceholder.typicode.com/posts",{
            title:"axios post test",
            body :" axios is fun!!!",
            userName : "홍길동"
        })
        .then(res =>{
            console.log(res.data);//데이터 로그 찍기
            //만약 Title콘솔로 찍고 싶다면 -> 데이터는 배열로 가지고 오게 됨 -> 
            
        })
        .catch(err =>{
            console.log(err); //오류 찍기
        })
    </script>
</head>
<body>
   
</body>
</html>

 

3) 요청 인터셉터 설정 

요청이 발생하기 전에 선 실행되는 것

모든 요청에 동일하게 적용되어야 하는 것

 

EX)

클라이언트가 요청한다고 데이터를 다 주면 안됨. 권한을 확인하는 작업 등을 거쳐야함

1)헤더에 Authon~ -> 하나하나 붙이는 것이 아니라 다 붙여질 수 있도록

 

 

3) 응답 인터셉터 설정 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        //요청 데이터 선행 처리
        axios.interceptors.request.use(config => {
            config.headers.Authorization = `Bearer MY_ACCESS_TOKEN`;
            return config;
        }, error => {
            return Promise.reject(error);
        });
        //응답 데이터 선행 처리
        axios.interceptors.response.use(response => {
            console.log('Interceptor response data',response.data)
            return Promise.resolve;
        }, error => {
            return Promise.reject(error);
        });
       
        axios
        .post("https://jsonplaceholder.typicode.com/posts", {
            title: "axios post test",
            body: "axios is fun!!!",
            userName: "홍길동"
        })
        .then(res => {
            console.log(res.data);
        })
        .catch(err => {
            console.log(err);
        });
    </script>
</head>
<body>
   
</body>
</html>

 

 

 

post 방식으로 데이터를 요청하는 것은 데이터를 만들어달라는 것과 같음 

 

 

 

 

인터셉터에서 한번, 응답에서 한 번 

 


2교시

 

국가 정보를 가져와서 화면에 출력해보자!

출력 내용 

1. 국가명

2. 국기 이미지

3. 지도 링크

 

 

#1 국가 정보를 제공하는 REST API 

https://restcountries.com/v3.1/all

필드 설명

https://gitlab.com/restcountries/restcountries/-/blob/master/FIELDS.md

 

FIELDS.md · master · restcountries / restcountries · GitLab

GitLab.com

gitlab.com

 

 

flag 국기

maps 지

 

좌 우리나라 이름, 우 우리나라 국기

 

#2 실행에 필요한 자바 스크립트 라이브러리 추가

통신을 위한 : axios

데이터 처리를 위한 jquery

 

1. 국가 정보를 제공하는 API 가져오기

2. 실행에 필요한 JavaScript 라이브러리 추가

3. axios를 이용해서 국가 데이터를 조회

4. 가져온 데이터를 <li> 요소로 출력

5. 부트스트랩 적용

6. 특정 단어만 들어간 국가만 필터링해서 출력되도록

코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios, jquery 라이브러리 추가 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <script>


    </script>
</head>
<body>
    <h1>국가 정보를 가져와서 출력</h1>
   
</body>
</html>

 

2. 국가 데이터 조회 -> GET 요청

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios, jquery 라이브러리 추가 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <script>
        axios.get("https://restcountries.com/v3.1/all")
        .then(res =>{
            console.log(res);
        })
        .catch(err =>{
            console.log(err);
        })
    </script>
</head>
<body>
    <h1>국가 정보를 가져와서 출력</h1>
   
</body>
</html>

 

2.1)출력 -> 콘솔창

<ul></ul> <!--순서에 관계 없는 데이터 (순서가 중요하지 않음)-->

 

2.1)출력 -> 특정 데이터만 

데이터.이름..오피셜

 

 

코드 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios, jquery 라이브러리 추가 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <script>
        axios.get("https://restcountries.com/v3.1/all")
        .then(res => {
            console.log(res);
            res.data.forEach(country => {
                /*
                console.log(country.name.official);
                console.log(country.flags.png);
                console.log(country.maps.googleMaps);
                console.log(country.maps.openStreetMaps);
                console.log("---------------");
                */
                const li = `
                    <li>
                        <img src="${country.flags.png}" alt="${country.flags.alt}" />
                        <p>${country.name.common} (${country.name.official})</p>
                    </li>
                `;
                $('ul').append(li);
            });
        })
        .catch(err => {
            console.log(err);
        });
    </script>
</head>
<body>
    <h1>국가 정보를 가져와서 출력</h1>


    <ul>
        <!--
        <li>
            <img src="https://flagcdn.com/w320/ni.png" alt="국기설명" />
            <p>일반국가명 (공식국가명)</p>
        </li>
        -->
    </ul>
   
</body>
</html>

 

스타일 처리

 

 

그럼에도 안 예뻐서 부트 스트랩을 적용해보자!

 

3. 부트스트랩 적용

CSS 파일이 필요

반응형 웹 디자인 프론트 프레임 워크

미리 선언되어 있는 것을 가져옴

 

 <h1 class = "text-center text-primary mb-4">국가 정보를 가져와서 출력</h1>

text-center : 글자 가운데 정렬

text-primary : 글자 색상

mb-4 글자 마진(mofgin bottom)

 

<ul class ="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-3">
    </ul>

한줄에 1개, 중간 화면은 한줄에 2개, 큰 화면은 한줄에 3개 

뷰의 크기가 변경될 때 이미지 개수 변경

g-3 : 안에 간격, 그리드  

 

li 는 자바스크립트를 통해 제작

 

 <li class ="d=flex align-items-center border p-3 bg-white rounded shadow-sm">

flex : 

align-tiems-center : 가운데 정렬 

 

  <img src="${country.flags.png}" alt="${country.flags.alt}" 
                        class = "img-fluid rounded"/>

 

rounded : 이미지 둥글게

p class ="mb-0 ms-3

 

 

실행 화면

 

 

전체 코드

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios, jquery 라이브러리 추가 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <!-- Bootstrap JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
    <script>
        axios.get("https://restcountries.com/v3.1/all")
        .then(res => {
            console.log(res);
            res.data.forEach(country => {
                const li = `
                    <li class="d-flex align-items-center border p-3 bg-white rounded shadow-sm">
                        <img src="${country.flags.png}" alt="${country.flags.alt}" class="img-fluid rounded" />
                        <p class="mb-0 ms-3">${country.name.common} (${country.name.official})</p>
                    </li>
                `;
                $('ul').append(li);
            });
        })
        .catch(err => {
            console.log(err);
        });
    </script>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">    
    <style>
        img { width: 100px; height: auto; margin-right: 10px; }
        /*
        p { display: inline; }
        */
        ul { padding: 0; }
        li { list-style-type: none; margin-bottom: 20px; }
    </style>
</head>
<body class="bg-light">
    <div class="container my-5">
        <h1 class="text-center text-primary mb-4">국가 정보를 가져와서 출력</h1>
        <ul class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-3"></ul>
    </div>
</body>
</html>

 

 

4. 특정 단어만 들어간 국가만 필터랭해서 출력!

입력창 추가

 <h1 class="text-center text-primary mb-4">국가 정보를 가져와서 출력</h1>
        <div class="d-flex justify-content-center mb-4">

 

 

현재 입력된 내용 출력

 

   <script>
        $('input').on('keyup', e => {
            const inputText = $(e.currentTarget).val();
            console.log(inputText);    // 현재 입력창에 입력된 내용(글자)
        });
    </script>


 

 

데이터 필터링 하기

 <script>
        $('input').on('keyup', e => {
            const inputText = $(e.currentTarget).val().toLowerCase();
            console.log(inputText);    // 현재 입력창에 입력된 내용(글자)
            //서버로부터 가져온 국가 정보에서 국가명에 입력창의 내용이 포함된 건만 추출해서 출력
            //~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~~~~~  <== inputText |  ~~~~~~~~~~~~`   ~~~
            //datas                          datas[*].name.comon                                    showCountry()
            //                               datas[*].name.offical              +-- Array.filter()    
        
            
            //데이터 필터링 -> showcountryinfo에 던져주기기
            const filtedData = datas.filter(data=>
                data.name.common.toLowerCase(inputText) >=0 || 
                data.name.official.indexOf.toLowerCase(inputText) >0
            );
            showCOuntryInfo(filtedData);
        });
    </script>

 

데이터를 필터링 후 -> showcountryinfo 함수에 보여주기

 

데이터 보여주는 함수

 

  const showCOuntryInfo = countryInfos => {
            //비우기
            $('ul').empty();
            countryInfos.forEach(country => {
                // 출력 로직
                const li = `
                    <li class="d-flex align-items-center border p-3 bg-white rounded shadow-sm">
                        <img src="${country.flags.png}" alt="${country.flags.alt}" class="img-fluid rounded" />
                        <p class="mb-0 ms-3">${country.name.common} (${country.name.official})</p>
                    </li>
                `;
                $('ul').append(li);
            });



        }

 

 

 

 const showCountryInfo = countryInfos => {
            $('ul').empty();
            countryInfos.forEach(country => {
                const li = `
                    <li class="d-flex align-items-center border p-3 bg-white rounded shadow-sm">
                        <img src="${country.flags.png}" alt="${country.flags.alt}" class="img-fluid rounded" />
                        <p class="mb-0 ms-3">${country.name.common} (${country.name.official})</p>
                    </li>
                `;
                $('ul').append(li);
            });    
        };

 

 

전체코드

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios, jquery 라이브러리 추가 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <!-- Bootstrap JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
    <script>
        // 서버로 부터 가져온 전체 국가 정보를 저장할 배열
        let datas = [];


        // 국가 정보를 담고 있는 배열을 출력
        const showCountryInfo = countryInfos => {
            $('ul').empty();
            countryInfos.forEach(country => {
                const li = `
                    <li class="d-flex align-items-center border p-3 bg-white rounded shadow-sm">
                        <img src="${country.flags.png}" alt="${country.flags.alt}" class="img-fluid rounded" />
                        <p class="mb-0 ms-3">${country.name.common} (${country.name.official})</p>
                    </li>
                `;
                $('ul').append(li);
            });    
        };


        axios.get("https://restcountries.com/v3.1/all")
        .then(res => {
            datas = [...res.data];
            showCountryInfo(res.data);
        })
        .catch(err => {
            console.log(err);
        });
    </script>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">    
    <style>
        img { width: 100px; height: auto; margin-right: 10px; }
        /*
        p { display: inline; }
        */
        ul { padding: 0; }
        li { list-style-type: none; margin-bottom: 20px; }
    </style>
</head>
<body class="bg-light">
    <div class="container my-5">
        <h1 class="text-center text-primary mb-4">국가 정보를 가져와서 출력</h1>
        <div class="d-flex justify-content-center mb-4">
            <input type="text" class="form-control" placeholder="검색할 국가명을 입력하세요." />
        </div>
        <ul class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-3"></ul>
    </div>


    <script>
        $('input').on('keyup', e => {
            const inputText = $(e.currentTarget).val().toLowerCase();
            console.log(inputText);    // 현재 입력창에 입력된 내용(글자)
            // 서버로부터 가져온 국가 정보에서 국가명에 입력창의 내용이 포함된 건만 추출해서 출력
            // ~~~~~~~~~~~~~~~~~~~~~~~~     ~~~~~   ~~~~~~~~~~~~   ~~~~~~~~~~~~~~     ~~~
            // datas              datas[*].name.common     inputText    |             showCountryInfo()
            //                    datas[*].name.official                +-- Array.filter()  


            const filteredData = datas.filter(data =>
                data.name.common.toLowerCase().indexOf(inputText) >= 0 ||
                data.name.official.toLowerCase().indexOf(inputText) >= 0
            );
            showCountryInfo(filteredData);
        });
    </script>
</body>
</html>

 

 

TODO.

 

 

1. 검색 결과로 조회된 국가 개수를 출력하는 코드를 추가

2. 국가명 아래에 구글 지도와 Open Street Map 지도를 보여주는 링크를 추가 

  (링크를 클릭하면 지도가 새창에서 열리도록)

 


 

모듈

소프트웨어를 개발할 때 하나의 독립적인 단위, 특정 기능을 캡슐화해서 다른 코드와 분리한 코드의 집합

모듈을 사용하면 코드 재사용성을 높이고, 관리와 유지보수를 쉽게 하며, 복잡한 시스템을 더 작은 단위로 나누어 개발

 

모듈을 사용하면 코드 재사용성을 높이고, 관리와 유지보수를 쉽게 하며, 복잡한 시스템을 더 작은 단위로 나누어 개발하는 것이 가능

 

+ 꼭 읽어볼 것

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Modules

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/export

 

 

리액트 앱 개발

일반 웹 페이지에 react.js  파일을 추가해서 기능을 구현

 

1. react 폴더 생성 및 폴더 구조

2.

 

 

1. DOM 컨테이너 추가

리액트 파일 추가

리액트 컴포넌트 추가

react.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!--#1 HTML 파일에 DOM 컨테이너를 추가-->
                     <!--
                       ~~~~
                       React DOm Node -> Virtul Dom의 시작점    
                     -->
    <div id="root"></div>

     <!--#2 리액트 파일(react.js,react-dom.js) 추가-->
     <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

    <!--#3 리액트 컴포넌트 코드를 추가-->
    <script src="MyButton.js"></script>

</body>
</html>

 

 

Mybuttonjs

 

//props로 이동
function MyButton(props) {

    //배열 비구조화
    //isClicked = false, setIsClicked = useState(false) 에서 반환해주는 값을 받아줌
    const [isClicked, setIsClicked] = React.useState(false);
//hook 이라는 함수

    //<button onClick = "setIsClicked(true)" => Cliecked</button
    return React.createElement(

        "button", 
        //attribute
        { onClick: () => setIsClicked(!isClicked) },
        isClicked ? "Clicked" : "Click here"
    );

    
}

    //내가 보고 있는 문서 중 ID가 root인 것에서 넘겨줌줌
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(React.createElement(MyButton));

 

MyButton 컴포넌트 정의:

MyButton이라는 함수형 컴포넌트를 정의합니다. props는 컴포넌트에 전달되는 속성을 나타내지만, 이 예제에서는 사용되지 않습니다.

function MyButton(props) {

 

 

상태 관리:

useState 훅을 사용하여 isClicked라는 상태 변수를 정의합니다. 초기값은 false입니다. setIsClicked는 이 상태를 업데이트하는 함수입니다

const [isClicked, setIsClicked] = React.useState(false);

버튼 생성:

  • React.createElement를 사용하여 <button> 요소를 생성합니다.
  • onClick 속성에 화살표 함수를 할당하여 버튼이 클릭될 때 setIsClicked를 호출합니다. 이 함수는 isClicked의 현재 값을 반전시킵니다.
  • 버튼의 텍스트는 isClicked의 값에 따라 "Clicked" 또는 "Click here"로 변경됩니다.
return React.createElement(
    "button", 
    { onClick: () => setIsClicked(!isClicked) },
    isClicked ? "Clicked" : "Click here"
);

 

루트 요소에 컴포넌트 렌더링:

  • document.getElementById("root")를 사용하여 HTML 문서에서 ID가 "root"인 요소를 찾습니다.
  • ReactDOM.createRoot를 사용하여 해당 요소에 React의 루트를 생성합니다.
  • root.render를 호출하여 MyButton 컴포넌트를 렌더링합니다.
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(React.createElement(MyButton));

 

 

 

JSX (JavaScript + XML) : 자바 스크립트 확장 문법

                         

                          HTML == > XML

                          ~~~~~~~~~~~~~~~~~~~~

const element = <h1> hello,World !</h1>

~~~~~~~~~~~~

          |

          +-----------JavaScript---------------------->

<html  태그 형태로 쓰다가 %%>

 

 

const element = React.createElemnt("h1",{},"Hello,World)

 

위의 형태가 훨씬 더 보기 편함

 

 

CRA (create-react-app) , CNA(create-next-app)(최근)

리액트 기반 웹 애플리케이션 개발에 필요한 모든 설정 상태의 프로젝트를 만들어주는 도구

 

CNA 설

c:\react> npx create-next-app
√ What is your project named? ... my-next-app
√ Would you like to use TypeScript? ... No / Yes
√ Would you like to use ESLint? ... No / Yes
√ Would you like to use Tailwind CSS? ... No / Yes
√ Would you like your code inside a `src/` directory? ... No / Yes
√ Would you like to use App Router? (recommended) ... No / Yes
√ Would you like to use Turbopack for `next dev`? ... No / Yes
√ Would you like to customize the import alias (`@/*` by default)? ... No / Yes

 

생성 완료

 

 

# 프로젝트 디렉토리로 이동해서 개발 서버를 실행해보자

앞에서 만들었던 버튼 앱을 JSX 구문을 이용해서 구현 

 

CRA

c:\react\my-cra-app\src\MyButton.js

import { useState } from "react";



function MyButton(props) {

    const [isClicked, setIsClicked] = useState(false);



    /*

    return React.createElement(

        "button",

        { onClick: () => setIsClicked(!isClicked) },

        isClicked ? "Clicked" : "Click here"

    );

    */

    return (

        <button onClick={() => setIsClicked(!isClicked)}>

            {isClicked ? "Clicked" : "Click here"}

        </button>

    );

}

export default MyButton;



c:\react\my-cra-app\src\App.js

import MyButton from "./MyButton";



function App() {

  return (

    <MyButton />

  );

}



export default App;


 

CNA

C:\react\my-next-app\src\pages\MyButton.js

 

import { useState } from "react";



function MyButton(props) {

    const [isClicked, setIsClicked] = useState(false);



    /*

    return React.createElement(

        "button",

        { onClick: () => setIsClicked(!isClicked) },

        isClicked ? "Clicked" : "Click here"

    );

    */

    return (

        <button onClick={() => setIsClicked(!isClicked)}>

            {isClicked ? "Clicked" : "Click here"}

        </button>

    );

}

export default MyButton;

 



C:\react\my-next-app\src\pages\index.js

import MyButton from "./MyButton";



export default function Home() {

  return (

    <MyButton />

  );

}





XSS(Cross-Site Scripting, 크로스 사이트 스크립팅)

공격자가 전달한 스크립트 코드가 사용자 브라우저를 통해서 실행되는 공격 기법 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

희생자 브라우저에서 공격자가 전달한 스크립트 코드가 실행되면, 

희생자 브라우저 또는 PC에 저장된 정보를 탈취 ⇒ Cookie

가짜 페이지를 만들어 사용자 입력을 유도해서 입력한 정보를 탈취 

해당 PC의 제어권을 탈취해서 원격에서 제어 ⇒ BeeF와 공격 프레임워크를 활용해서 가능 







홍길동

글쓰기 페이지   ----------------------------> 글저장 

<script> alert('xss') </script>               <script> alert('xss') </script>

                                              &lt;script&gt; alert('xss') &lt;/script&gt;

                                                      |

고길동                                                |

글읽기 페이지  <--------------------------------------+

<script> alert('xss') </script>



XSS(Cross-Site Scripting, 크로스 사이트 스크립팅)

공격자가 전달한 스크립트 코드가 사용자 브라우저를 통해서 실행되는 공격 기법 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

희생자 브라우저에서 공격자가 전달한 스크립트 코드가 실행되면, 

  • 희생자 브라우저 또는 PC에 저장된 정보를 탈취 ⇒ Cookie
  • 가짜 페이지를 만들어 사용자 입력을 유도해서 입력한 정보를 탈취 
  • 해당 PC의 제어권을 탈취해서 원격에서 제어 ⇒ BeeF와 공격 프레임워크를 활용해서 가능 







홍길동

글쓰기 페이지   ----------------------------> 글저장 

<script> alert('xss') </script>               <script> alert('xss') </script>

                                                      |

고길동                                                |

글읽기 페이지  <--------------------------------------+

<script> alert('xss') </script>


방어 기법

스크립트 코드가 실행되지 않도록 저장할 때 인코딩해서 저장하거나, 안전한 형태로 변경해서 저장, 내보낼 때 안전한 형태로 변경

CSP(컨텐츠 보안 정책)

https://developer.mozilla.org/ko/docs/Web/HTTP/CSP

근원적으로 차단 개발자가 만든 것인지 공격자가 만든 것인지 구분 -> 데이터를 신뢰할 수 있는지 없는지 함께 전

 

+ 브라우저 - CSP  mdn CORS, SOAP, 

 

JSX 사용법

create-react-app으로 생성한 my-cra-app 프로젝트의 App.js 파일을 수정하면서 실습을 진행

 

개발 서버 실행(기존 개발 서버를 종료 ctrl +c)

create-react-app으로 생성한 my-cra-app 프로젝트의 App.js 파일(C:\react\my-cra-app\src\App.js)을 수정하면서 실습을 진행

 

개발 서버 실행 (기존 개발 서버를 종료)

c:\react\my-next-app> cd c:\react\my-cra-app

c:\react\my-cra-app> npm start



#1 반드시 부모 요소 하나로 감싸야 한다. 

function App() {

  return (

    <h1>리액트 앱</h1>

    <h2>react app</h2> ⇐ JSX 식에는 부모 요소가 하나 있어야 합니다.

  );

}

 

export default App;

 

방법1. 다른 태그를 추가 ⇒ 불필요한 태그가 추가

 

function App() {

  return (

    <div>

      <h1>리액트 앱</h1>

      <h2>react app</h2>

    </div>

  );

}

export default App;





방법2. Fragment 컴포넌트를 이용 ⇒ 불필요한 태그 추가를 방지

 

import { Fragment } from "react";



function App() {

  return (

    <Fragment>

      <h1>리액트 앱</h1>

      <h2>react app</h2>

    </Fragment>

  );

}

export default App;

 



방법3. Fragment를 축약 방식으로 사용

 

// import { Fragment } from "react";



function App() {

  return (

    <>

      <h1>리액트 앱</h1>

      <h2>react app</h2>

    </>

  );

}

export default App;



#2 JSX 안에서는 자바스크립트 표현식을 { }로 감싸서 작성

function App() {



  const name = "홍길동";

  const age = 23;



  return (

    <>

      <h1>{`안녕, ${name}`}</h1>

      <h1>안녕, {name}</h1>

      <h2>{age + 2}</h2>

    </>

  );

}

export default App;

#3 JSX 내부에서 자바스크립트의 if 문을 사용할 수 없으므로, 삼항 연산자를 사용해야 함

function App() {



  const name = "홍길동";

  const age = 23;



  return (

    <>

      <h1>{`안녕, ${name}`}</h1>

      <h1>안녕, {name}</h1>

      <h2>${age + 2}</h2>

      <h2>{name === "홍길동" ? "환영합니다." : "환영하지 않습니다."}</h2>

    </>

  );

}

export default App;




#4 조건을 만족할 때만 내용을 보여주는 경우 ⇒ 조건부 렌더링

방법1. 삼항 연산자를 이용하는 방법 ⇒ 조건을 만족하지 않는 경우 null을 반환 

function App() {



  const name = "홍길동x";

  const age = 23;



  return (

    <>

      <h1>{`안녕, ${name}`}</h1>

      <h1>안녕, {name}</h1>

      <h2>${age + 2}</h2>

      <h2>{name === "홍길동" ? "환영합니다." : null}</h2>

    </>

  );

}

export default App;

 

방법 2. && 연산을 이용

 

&& 둘 다 True일 때 : True , 둘 중 하나가 False -> False

|| -> 둘다 false일 때 -: false , 둘 중 하나가 True -> True

 

<h2>{name === "홍길동" && "환경합니다."}</h2>
import MyButton from "./MyButton";
import { Fragment } from "react";

function App() {

  const name = "홍동";
  const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
      <h1>안녕, {name}</h1>
      <h2>{age+2}</h2>
      {/* <h2>{name === "홍길동" ? "환영합니다.":null}</h2> */}
      {/* 둘 다 True여야 True */}
                                  ~~~조거늘 만족했을 때 출력할 내용
      <h2>{name === "홍길동" && "환경합니다."}</h2> 
    </>
  );
}
export default App;

#4인라인 스타일

태그 내에서 style을 속성을 애용해서 스타일을 지정해주는 방법 

이외 인터널, 익스터널

 

DOM요소에 스타일을 지정할 때는 객체 형태로 적용해야 하며, 스타일 이름은 카멜 표현식을 사용하고, 숫자 타입의 경우 단위를 생략하면 기본값이 PX을 사용(단위를 포함할 때는 문자열로 표현)

 

import MyButton from "./MyButton";
import { Fragment } from "react";

function App() {

  const name = "홍길동";
  const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
                 {/* 
                 -표현식
                  -객체 표현
                 */}
      <h1 style ={{backgroundColor :"black", color : "yellow", fontSize : 28, padding: '16px'}}>안녕, {name}</h1>
      <h2>{age+2}</h2>
      <h2>{name === "홍길동" && "환경합니다."}</h2> 
    </>
  );
}
export default App;

Style을 적용할 때 중괄호 2개 밖에는 표현식, 안에는 객체

스타일은 객체로

실행 화면

Mystyle  따로 변수로 빼주어도 됨

 

import MyButton from "./MyButton";
import { Fragment } from "react";

function App() {

  const MyStyle ={backgroundColor :"black", color : "yellow", fontSize : 28, padding: '16px'};
  const name = "홍길동";
  const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
                 {/* 
                 -표현식
                  -객체 표현
                 */}
      <h1 style ={MyStyle}>안녕, {name}</h1>
      <h2>{age+2}</h2>
      <h2>{name === "홍길동" && "환경합니다."}</h2> 
    </>
  );
}
export default App;

 

스타일을 하나의 객체로 정의해서 규격화 하자

 

import MyButton from "./MyButton";
import { Fragment } from "react";

function App() {

  const MyStyle ={
    h1Style:{backgroundColor :"black", color : "yellow", fontSize : 28, padding: '16px'},
    h2Style:{color : 'red'}
  
  };
  const name = "홍길동";
  const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
                 {/* 
                 -표현식
                  -객체 표현
                 */}
      <h1 style ={MyStyle.h1Style}>안녕, {name}</h1>
      <h2 >{age+2}</h2>
      <h2 style ={MyStyle.h2Style}>{name === "홍길동" && "환경합니다."}</h2> 
    </>
  );
}
export default App;

 

#6 함수가 undefined를 반환하지 않도록 기본값을 설정

 

import MyButton from "./MyButton";
import { Fragment } from "react";

function Name(){
  let name;
  return name;
}
function App() {

  const MyStyle ={
    h1Style:{backgroundColor :"black", color : "yellow", fontSize : 28, padding: '16px'},
    h2Style:{color : 'red'}
  
  };
  // const name = "홍길동";
  // const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
                 {/* 
                 -표현식
                  -객체 표현
                 */}
      {/* <h1 style ={MyStyle.h1Style}>안녕, {name}</h1>
      <h2 >{age+2}</h2>
      <h2 style ={MyStyle.h2Style}>{name === "홍길동" && "환경합니다."}</h2>  */}
      안녕, <Name />!
    </>
  );
}
export default App;

 

 

만약 기본값이 정의되어 있지 않다면  ->  || 둘 다 False -> False

 

import MyButton from "./MyButton";
import { Fragment } from "react";

function Name(){
  let name;
  return name || "아무개";
}
function App() {

  const MyStyle ={
    h1Style:{backgroundColor :"black", color : "yellow", fontSize : 28, padding: '16px'},
    h2Style:{color : 'red'}
  
  };
  // const name = "홍길동";
  // const age = 23;
  return (
    <>
      {/* <h1>{'안녕',${name}}</h1> */}
                 {/* 
                 -표현식
                  -객체 표현
                 */}
      {/* <h1 style ={MyStyle.h1Style}>안녕, {name}</h1>
      <h2 >{age+2}</h2>
      <h2 style ={MyStyle.h2Style}>{name === "홍길동" && "환경합니다."}</h2>  */}
      안녕, <Name />!
    </>
  );
}
export default App;

 

 

#7 CSS 클래스를 사용할 때 class가 아닌 className으로 설정

 

<div class="myclass"> ... </div>

-> 오류

<div className="myclass"> ... </div>

class-> 자바 스크립트에서 이미 예약어로 사용중

import "./App.css";

function App() {
  return (
    <div className="react">홍길동</div>
  );
}
export default App;

#8 모든 태그는 반드시 닫는 태그를 사용 = > 내용이 없는 태그의 경우 셀프 클로징 태그를 사용해야 함

 

1. <input> <img> <hr> <br> ...

<input /> <img /> <hr /> <br /> ...

 

#9 주석(comment)

 

import "./App.css";

 

// 자바스크립트 주석

/*

   자바스크립트 주석 

*/

 

function App() {

  // 자바스크립트 주석

  /*

    자바스크립트 주석 

  */

 

  return (

    // 태그가 시작되기 전에는 자바스크립트 주석 사용이 가능 

    /*

      자바스크립트 주석 

    */

 

    <>

      // 태그가 시작되면 주석이 아닌 일반 문자열로 인식

      /*

         일반 문자열로 해석되어 화면에서 출력

      */

 

      { /* 자바스크립트 표현식으로 주석을 처리 */}

      { // 인라인 주석을 사용할 때는 유의해야 함 (표현식 끝에 }을 사용하면 주석 처리되어 버림)

      }

      <input type="text" />

      <input type="text"></input>

    </>

  );

}

 

// 자바스크립트 주석

/*

   자바스크립트 주석 

*/

 

export default App;


컴포넌트 

클래스형 컴포넌트와 함수형 컴포넌트 구조

 

클래스형 컴포넌트

 

import {Component} from "react";

 

class MyApp extends Component{

      render();

 -> 재정의 되어야 함, 화면에 보여지는 내용을 반환 -> 무언가 출력되는지 트위터인지, 페이스북인지 플랫폼에  컴포넌ㅌ의 내용물이 달라지기 때문

          return{

                <>  </>

);

 

}

export default MyApp; -> 모듈화

 

 


함수형 컴포넌트

 

function MyApp() {

     return (

         <>   </>

     );

}

export default MyApp;

 

함수 표현식으로 변경

const MyApp = function() {

     return (

         <>   </>

     );

}

export default MyApp;


화살표 함수 변경

const MyApp = () => {

     return (

         <>   </>

     );

}

export default MyApp;