본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[80일차 복습] React 리액트, 웹팩, CSS 연결, 반응형 / Header 만들기

반응형

기본 세팅 

 

어제 만든 webpack 환경 설정 을 바탕으로 아래 파일들을 복사해서 새로운 파일에 넣기! 

1. package.josn 

2. webpack.config.js

 

그리고 새로 아래의 파일들을 만들어 기본 코드 작성하기  

3. index.html

4. index.jsx

 

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="./dist/app.js"></script>
</body>
</html>

index.jsx (entry ----> output 은 App.js 로 설정 - 개발 환경에서는 dist / App.js 가 보이지는 않지만 돌아가고 있음!) 

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class App extends Component {
    render() {
        return (
            <>
                Hi !
            </>
        )
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('#root')
)

 

 

5. 현재 터미널의 위치 잘 체크 !! 해당 위치로 이동 

6. 아래 명령어로 package.json에 있는 라이브러리들 한번에 install 

$npm install 

 

아래와 같은 오류가 나는 경우

C:\Users\saeee_z18xmwt\OneDrive\문서\react_first_lesson0628\0706webpack\0706header_practice>npm i npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: 0705webpack@1.0.0 npm ERR! Found: react-refresh@0.10.0 npm ERR! node_modules/react-refresh npm ERR! dev react-refresh@"^0.10.0" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer react-refresh@">=0.8.3 <0.10.0" from @pmmmwh/react-refresh-webpack-plugin@0.4.3 npm ERR! node_modules/@pmmmwh/react-refresh-webpack-plugin npm ERR! dev @pmmmwh/react-refresh-webpack-plugin@"^0.4.3" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! See C:\Users\saeee_z18xmwt\AppData\Local\npm-cache\eresolve-report.txt for a full report. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\saeee_z18xmwt\AppData\Local\npm-cache\_logs\2021-07-06T06_44_42_704Z-debug.log

아래 명령어 실행

$ npm install -D @pmmmwh/react-refresh-webpack-plugin --save --legacy-peer-deps

또 안되면 아래 명령어 실행 

$ npm install webpack -D 

 

7. webpack 실행하기 

npm run dev

 

 

 

 

<- 잘 나온다 ! 

 

 

 

 

 

 

위 명령어는 package.json 에서 설정해주었기 때문 !   

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack server --env development"
  },

npx webpack은 이제 명령어 실행이 안됨 ! 

 

 

 

 

기본 세팅 끝 


 

 

 

웹팩 개발 환경 구축 후, 이제 Components를 여러개 만들어서 연결시켜보기 ! + CSS 

index 최상단 부모 (using ReactDOM) <- App 연결 <- FuncComp & ClassComp 연결 시키기

 

App, FuncComp, ClassComp 모두 모듈로 뺄 것 -> 총 4개의 파일로 쪼개진다. 

App은 ul tag로 , App에 연결할 Func, ClassComp는 li tag 로 ! 

 

1. 아래와 같은 폴더/파일 트리 만들기 

2. index.jsx 에 App 연결

index.jsx

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import App from './App'      // App 불러오기 


ReactDOM.render(
    <App />,
    document.querySelector('#root')
)

App.jsx

import React, {Component} from 'react';

class App extends Component {
    render() {
        return (
            <ul>
                <h2>Hi !</h2>
            </ul>
        )
    }
}

export default App

 

3. App.jsx 에 ClassComp, FuncComp 연결하기

 

ClassComp.jsx

import React, {Component} from 'react';

class ClassComp extends React.Component{
    render(){
        return(
            <li className="funccomp">
                I am ClassComp covered by 'li' tag
            </li>
        )
    }
}

export default ClassComp

FuncComp.jsx

import React from 'react';

const FuncComp=()=>{
    return (
        <>
            <li className="classcomp">I am FuncComp1 covered by 'li' tag</li>
            <li className="classcomp">I am FuncComp2 covered by 'li' tag</li>
        </>
    )
}

export default FuncComp

App.jsx 에서 위의 components 불러와서 사용하기

import React, { Component } from 'react';
import ClassComp from './components/ClassComp'
import FuncComp from './components/FuncComp'


class App extends Component {
    render() {
        return (
            <>
                <h2>Hi !</h2>
                <ul className="comp">
                    <ClassComp />
                    <FuncComp />
                    <ClassComp />
                    <FuncComp />
                </ul>
            </>
        )
    }
}

export default App

$ npm run dev -> http:localhost:8000 가면 

 

 

* className은 미리 넣음 

 

 


 

 

위의 중간 완성본에 CSS 연결하기

CSS 연결은 두 가지 방법이 있다. 

 

 

첫 번째 방법 : 웹페이지에서 만드는 방식  

 

1. css 폴더 > index.css 파일 만들기 

2. html 에 css 연결

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./css/index.css">    // css 연결 
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="./dist/app.js"></script>
</body>
</html>

3. css 코드 작성 

index.css

*{ margin:0; padding:0;}

ul,li{
    list-style:none;
    padding:5px;
    margin:5px;
}

ul{
    text-align: center;
}

h2{
    text-align: center;
}


body{
    background-color: cadetblue;
    color: black;
}

.comp{
    border:2px solid white;
}

.classcomp{
    border:2px solid red;
}

.funccomp{
    border:2px solid blue;
}

 

 


 

 

두 번째 방법 : 웹팩을 이용해서 만드는 방법 

웹팩을 이용해서 만드는 방법도 두 가지이다.

1) 하나의 css마다 style tag 도 한 개씩 추가하는 방법

2) 모든 css를 하나의 style tag 로 합쳐서 추가하는 방법 

 

 

1) 하나의 css마다 style tag 도 한 개씩 추가하는 방법

 

1. 서버를 끄고 html의 css 연결된 코드 한줄 삭제  & 아래 명령어 실행

$ npm i -D css-loader   // react 파일에서 css 불러오는 능력 有 (react page에서 import css 코드 가능하게함)
$ npm i -D style-loader   // css-loader가 가지고 온걸 style tag로 감싸는 아이
$ npm i -D mini-css-extract-plugin   // 여러개의 css 들을 하나로 합치기 -> style 하나만 head에 추가되도록 

 

2. webpack.config.js 수정

rules의 두 번째 요소 {} 객체 추가, 객체 안에는 test, use 사용 

const path = require('path')
const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') 
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')


module.exports = {  //module.exports부터 무조건 쓰기 ! 
    name:'firstWebpack', //webpack의 이름  / 안적어도 된다. 
    mode:'development', //어떤 용도로 개발을 할 것이냐 
    devtool:'eval',   // eval -> 개발용 , hidden-source-map -> 배포용 

    resolve:{
        extensions:['.js', '.jsx']
    },

    entry:{
        app:['./index.jsx']
    },

    // module을 통해 babel or sth 통해 해석해야하는구나 알도록 설정
    // 외부파일 가져와서 읽을 때 사용하는 
    // babel은 js 뿐만 아니라 다른 파일도 읽을 수 있음 -> 규칙 정해주기
    module:{              
        rules:[{
            test:/\.jsx?$/,  //확장자 .js / .jsx 가능하게
            loader:'babel-loader', // webpack - babel 이해해주는 아이
            // babel 내용 바꾸고 싶을 때 ex) plugin, preset..
            options:{
                presets:[
                    ['@babel/preset-env', {
                        targets:{
                            browsers:['>5% in KR','last 2 chrome versions']
                        },
                        debug:true,
                    }], 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/babel'
                ]
            }
        },{
            test:/\.css$/,                                           //수정 111
            //js에서 css파일 읽어서 어떻게 작동시킬지 적기 
            //뒤에 있는 css-loader부터 실행 -> style-loader 실행 
            //style-loader는 css-loader 없이 사용이 안됨! 
            use:['style-loader,'css-loader']  
        }]
    },


    plugins:[
        new webpackPlugin(),
        new webpack.LoaderOptionsPlugin({debug:true}),
    ],

    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js', 
        //정적 파일로 바꾼다. 
        publicPath:'/dist'
    },

    // 실행할 때 
    devServer:{
        publicPath:'/dist',
        hot:true, // hot reload 
    }
}

-

        },{
            test:/\.css$/,                                           //수정 111
            //js에서 css파일 읽어서 어떻게 작동시킬지 적기 
            //뒤에 있는 css-loader부터 실행 -> style-loader 실행 
            //style-loader는 css-loader 없이 사용이 안됨! 
            use:['style-loader,'css-loader']  
        }]

test: 정규식 사용

use: ['style-loader', 'css-loader']

1) css-loader가 먼저 실행되고

2) style-loader 가 두 번째로 실행됨 (style-loader는 css-loader가 꼭 필요 !) 

 

 

 

 

3. index.jsx 에 import css 

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import App from './App'
import './css/index.css'


ReactDOM.render(
    <App />,
    document.querySelector('#root')
)

 

4. css의 funcComp & classComp 부분을 따로 나누어서 style 추가해보기

1) css > classComp.css / funcComp.css 생성 

2) css 옮겨 담기 (해당 component에 적용할 부분만) 

3) clasComponent / funcComponent 에 각각의 css import 하기

완성 ! 그런데 style이 추가한 만큼 나온다. 총 3개를 style tag 들을 한 개로 합쳐서 style 하나의 tag에 올려보기 

 

 

 


 

 

2) 모든 css를 하나의 style tag 로 합쳐서 추가하는 방법 

 

 

아까 npm 설치한 세 가지 명령 중 마지막 아래 명령이 여러개의 css를 하나의 style tag로 return 할 수 있게 만드는 것!

$ npm i -D mini-css-extract-plugin  

 

 

1. webpack.config.js 수정 

 

- 위에 설치한 내용 가져오기 + module>rules>두 번째 인자의 use의 첫번째 자리에 가져온 변수 안에 있는 loader입력 

('style-loader'삭제하고 MiniCssExtractPlugin.loader 입력 

- plugin에서 파일명 정해서 해당 매서드 실행 -> output 에서 지정한 경로  -> 절대경로 + dist 에 app.css 가 생긴다. (개발자 모드라 dist파일 / app.css / app.js 가 보이지않는다) 

const path = require('path')
const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')  
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') //추가 1111


module.exports = {  //module.exports부터 무조건 쓰기 ! 
    name:'firstWebpack', //webpack의 이름  / 안적어도 된다. 
    mode:'development', //어떤 용도로 개발을 할 것이냐 
    devtool:'eval',   // eval -> 개발용 , hidden-source-map -> 배포용 

    resolve:{
        extensions:['.js', '.jsx']
    },

    entry:{
        app:['./index.jsx']
    },

    // module을 통해 babel or sth 통해 해석해야하는구나 알도록 설정
    // 외부파일 가져와서 읽을 때 사용하는 
    // babel은 js 뿐만 아니라 다른 파일도 읽을 수 있음 -> 규칙 정해주기
    module:{
        rules:[{
            test:/\.jsx?$/,  //확장자 .js / .jsx 가능하게
            loader:'babel-loader', // webpack - babel 이해해주는 아이
            // babel 내용 바꾸고 싶을 때 ex) plugin, preset..
            options:{
                presets:[
                    ['@babel/preset-env', {
                        targets:{
                            browsers:['>5% in KR','last 2 chrome versions']
                        },
                        debug:true,
                    }], 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/babel'
                ]
            }
        },{
            test:/\.css$/, 
            use:[MiniCssExtractPlugin,'css-loader']  /////  수정    11111
        }]
    },


    plugins:[
        new webpackPlugin(),
        new webpack.LoaderOptionsPlugin({debug:true}),
        //() 매서드 실행시켜주기 
        // app.css 파일 명으로 만들어서 하나로 묶어 주겠다. 
        new MiniCssExtractPlugin({filename:'app.css'}) /////     수정 222
        // 그럼 아래에 output 경로로 css 가 생긴다. 
    ],

    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js', 
        //정적 파일로 바꾼다. 
        publicPath:'/dist'
    },

    // 실행할 때 
    devServer:{
        publicPath:'/dist',
        hot:true, // hot reload 
    }
}

실행시켜보기 

app.js 가 잘 나온 걸 확인 후 다음 단계로!

 

 

2. 방금 만들어 낸 app.css를 index.html 에 추가

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./dist/app.css">  //추가 
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="./dist/app.js"></script>
</body>
</html>

head 에 style이 하나로 잘 나온다 

 

 

CRA로 웹팩 환경 구출을 하게되면 위의 기능이 react 기술이라고 오해할 수도 있다 ! 

요건 웹팩의 능력(?)이다. 

 

 


 

 

이제 위에서 연습해본 것들로 마지막 실습해보기 ! 

React, Webpack, CSS, 간단한 반응형까지 ! 

  header 만들어보기   

 

 

 

1. 웹팩 기본 개발환경 구축  

- package.json / webpack.config.js 복사 + 다른 파일들 생성 (위의 파일트리대로!) 

- terminal 현재 위치 조정 

- npm install 진행 (오류나면 위에 나온대로 처리!) 

$ npm install 

 

 

 

 

2. index.jsx <- app.jsx 연결 

index.jsx

import React, {Component} from 'react'
import ReactDOM from 'react-dom'

import App from './app'


ReactDOM.render(
    <App/>,
    document.querySelector('#root')
)

app.jsx

import React, { Component } from 'react';


class App extends Component {
    render() {
        return (
            <>
                hi I am App for heade-making 
            </>
        )
    }
}

export default App

$ npm run dev 로 연결 확인

브라우저 창

 

 

 

 

3. Navbar.jsx 코드 작성 + App 과 연결하기 

 

Navbar.jsx

import React, {Component} from 'react'
import '../css/navbar.css'

class Navbar extends Component{
    render(){
        return(
            <ul>
                <li>버튼1</li>
                <li>버튼2</li>
            </ul>
        )
    }
}

export default Navbar

app.jsx

import React, { Component } from 'react';
import Navbar from './component/Navbar'

class App extends Component {
    render() {
        return (
            <>
                <Navbar/>
            </>
        )
    }
}

export default App

 

 

 

4. react-icons 미리 만들어진 아이콘 패키지 다운

$npm i react-icons

위의 아이콘들을 볼 수 있는 곳 ! 

https://react-icons.github.io/react-icons/

 

React Icons

React Icons Include popular icons in your React projects easily with react-icons, which utilizes ES6 imports that allows you to include only the icons that your project is using. Installation (for standard modern project) npm install react-icons --save Usa

react-icons.github.io

 

 

5. Navbar.jsx에 아이콘 적용해보기 

import React, {Component} from 'react'
import '../css/navbar.css'
import {FaFacebook, FaInstagram, FaBeer} from 'react-icons/fa'

class Navbar extends Component{
    render(){
        return(
            <ul>
                <li><FaFacebook/></li>
                <li><FaInstagram/></li>
                <li><FaBeer> 한 쟌 </FaBeer></li>
            </ul>
        )
    }
}

export default Navbar

 

6. Navbar state에 social 배열 추가 + map 사용하여 반복 return 

(key 값은 id, url, icon 총 3가지) 

import React, {Component} from 'react'
import '../css/navbar.css'
import {FaFacebook, FaInstagram, FaTwitter} from 'react-icons/fa'

class Navbar extends Component{
    state={
        social:[
            {
                id:1,
                url:'https://www.twitter.com',
                icon:<FaTwitter/>
            },
            {
                id:2,
                url:'https://www.facebook.com',
                icon:<FaFacebook/>
            },
            {
                id:3,
                url:'https://www.instagram.com',
                icon:<FaInstagram/>
            },
        ]
    }




    render(){
        return(
            <ul>
                <li><FaFacebook/></li>
                <li><FaInstagram/></li>
                <li><FaBeer></FaBeer>굳</li>
            </ul>
        )
    }
}

export default Navbar

이제 요 위의 배열을 return에 map() 매서드를 통해 반복해서 return 하기 

 

 

    render() {
        return (
            <nav>
                <div className="nav-center">
                    <ul className="social-icons">
                        {
                            this.state.social.map(item=>{
                                let {id, url, icon} = item
                                return(
                                    <li key={id}>
                                        <a href={url}>{icon}</a>
                                    </li>
                                )
                            })
                        }
                    </ul>
                </div>
            </nav>
        )
    }

 

7. div 추가한 아래 li (text) 들을 다시 반복문으로 위와 동일하게 return 하기 

import React, { Component } from 'react'
import '../css/navbar.css'
import { FaFacebook, FaInstagram, FaTwitter, FaBars } from 'react-icons/fa'


class Navbar extends Component {
    state = {
        social: [
            {
                id: 1,
                url: 'https://www.twitter.com',
                icon: <FaTwitter />
            },
            {
                id: 2,
                url: 'https://www.facebook.com',
                icon: <FaFacebook />
            },
            {
                id: 3,
                url: 'https://www.instagram.com',
                icon: <FaInstagram />
            },
        ],
        menu:[
            {
                id:1,
                url:'/',
                text:'coconut'
            },
            {
                id:2,
                url:'/',
                text:'always'
            },
            {
                id:3,
                url:'/',
                text:'great'
            }
        ]
    }




    render() {
        return (
            <nav>
                <div className="nav-center">

                    {/* logo */}
                    <div className="nav-header">
                        <h1 className="logo">LOGO</h1>
                        <button className="nav-toggle">
                            <FaBars/>
                        </button>
                    </div>

                    {/* navigation */}
                    <div className="links-container">
                        <ul className="links">
                            {
                                this.state.menu.map(v=>{
                                    let {id, url, text} = v;
                                    return(
                                        <li key={id}>
                                            <a href={url}>{text}</a>
                                        </li>
                                    )
                                })
                            }
                        </ul>
                    </div>

                    <ul className="social-icons">
                        {
                            this.state.social.map(item=>{
                                let {id, url, icon} = item
                                return(
                                    <li key={id}>
                                        <a href={url}>{icon}</a>
                                    </li>
                                )
                            })
                        }
                    </ul>
                </div>
            </nav>
        )
    }
}

export default Navbar

 

 

8. css index.html / index.jsx 에 연결 

 

index.html   

webpack.config.js에서 MiniCssExtractPlugin  <- 이걸 사용해서 모든 css 합쳐서 한 개의 style tag 로 될 수 있도록 app.css 라는 파일을 dist 에 저장해놓음  -  요걸 적기 ! 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./dist/app.css">   <!--연결 --> 
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="./dist/app.js"></script>
</body>
</html>

 

index.jsx

import React, {Component} from 'react'
import ReactDOM from 'react-dom'

import App from './app'
import './css/index.css'

ReactDOM.render(
    <App/>,
    document.querySelector('#root')
)

 

Narbar.jsx

import React, { Component } from 'react'
import '../css/navbar.css'
import { FaFacebook, FaInstagram, FaTwitter } from 'react-icons/fa'
i

class Navbar extends Component {
    state = {
        social: [

 

 

 

 

9. Navbar.jsx 에 FaBar (반응형 시 햄버거모양 버튼!) 추가 + button tag 추가 

 

Navbar.jsx

import { FaFacebook, FaInstagram, FaTwitter, FaBars } from 'react-icons/fa'

                    {/* logo */}
                    <div className="nav-header">
                        <h1 className="logo">LOGO</h1>
                        <button className="nav-toggle">
                            <FaBars/>
                        </button>
                    </div>

 

 

10. css 작성

index.css

*{padding:0;margin:0;}


ul,li{list-style:none;}
a{ text-decoration:none;}


/* NavBar */

narbar.css

/* mobile */

.nav-header{
    display:flex;
    align-items: center;
    justify-content: space-between; /* 양쪽 끝 */
    padding:1rem;
}


.logo{
    font-size: 3rem;
}

/* rem 확대 축소 비율로 늘어남 */ 

.links-container{
    height:0;
    overflow:hidden;
}

.social-icons{
    height:0;
    overflow:hidden;
}

.nav-toggle{
    font-size:3rem;
    /*투명하게 만들기 */
    background:transparent;
    border-color:transparent;
    color:blue;
}

/* PC css style */
@media screen and (min-width:800px){


    .logo{
        font-size: 4rem;
    }

    .nav-toggle{
        /*pc 경우에 토글 안보이게*/ 
        font-size: 0px;
        color:blue;
    }

    .nav-center{
        max-width:1170px;
        margin:0 auto;
        display: flex;
        align-items:center;
        justify-content: space-between;
        padding:1rem;
    }

    .links-container{
        height:auto;

    }

    .links{
        display: flex;

    }
    .links>li>a{
        margin:0 0.5rem;
        color:black;
        font-size: 2rem;
    }

    .social-icons{
        display:flex;
        height:auto;
    }

    .social-icons>li>a{
        margin: 0 .5rem;
        color: darkcyan;
    }

}

 

PC
Mobile

 

 

웹팩 + css + React + 반응형 실습 끄읕

반응형