함수형 컴포넌트, Webpack,


세 가지 간단한 구현으로 웹팩과 기능적 구성 요소를 살펴보겠습니다.

1. 로그인 버튼을 누르면 로그아웃으로 전환, 다시 로그아웃을 누르면 로그인으로 전환

2. + 버튼을 누르면 1씩 증가하고 – 버튼을 누르면 1씩 감소합니다.

3. Axios를 통해 강아지 사진 가져오기 및 업데이트 시 다른 강아지 사진 가져오기

```sh
// 웹팩
npm init -y
npm i webpack webpack-cli html-webpack-plugin webpack-dev-server

//react
npm i react react-dom

//babel
npm i @babel/core @babel/preset-env @babel/preset-react babel-loader
// webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports ={
	name:'react-project',
    mode:'development', //실행을 할 때 개발모드로 할건지,배포모드로 할건지
    resolve:{
    	extensions:('.js'.'.jsx') // 모듈에서 파일 확장자를 처리하는 옵션, 파일을 처리할 때 해당 확장자를 생략
    }, //웹팩이 모듈을 해석할 때 사용하는 옵션 설정, 웹팩이 모듈을 찾는 과정에서 불필요한 요청을 줄여 빌드시간을 단축
    entry:'./src/index.jsx', // 진입지점
    plugins:( // 빌드과정에서 실행되는 플러그인 설정
    	new HtmlWebpackPlugin({
        	template:'index.html', //원본
            filename:'index.html' //번들링 될 파일이름
        })
    ),
    module:{
    	rules:({
        	test:/\.jsx?/,  //로더가 처리해야 할 파일을 지정하는 옵션, 문자열or정규식으로 설정
            loader:'babel-loader', //번들링 하기전에 바벨로 컴파일하기
            options:{
            	presets:('@babel/preset-env','@babel/preset-react'), //어떤 옵션으로 바벨을 통해서 컴파일 할껀지
                plugins:() //로더에 의해 처리된 모듈에 대해 추가적인 작업을 수행하는 플러그인을 지정하는 옵션
            }
        })
    },
    output:{
    	filename:'bundle.js',
        path:path.join(__dirname,'dist')
    }, // 번들링 된 파일과 경로지정
    devServer:{ //웹팩 개발 서버를 사용하여 개발을 보다 빠르고 편리하게 진행, express server안만들어도됨
    	static:{
        	directory:path.join(__dirname,'dist')
        }, // 정적파일지정하여 보여줌
        compress:true, // true 설정 시 네트워크 대역폭 절약, 개발서버에서 응답 시 파일을 gzip압축하여 전송하는 것
        port:3000,
        hot:true, //소스코드 변경 시 자동으로 새로고침
        historyApiFallback:true //true 설정시 url이 존재하지 않을 때 index.html파일을 서버에서 제공,SPA에서 404응답 받았을 때 대체 페이지 옵션
    } //즉 웹팩개발서버를 설정하는 것, 개발 서버가 실행되면서 파일 변경을 감지하고 자동으로 빌드
}

1. 로그인 상태 버튼

src/pages/login.jsx

import React, {useState, useEffect} from 'react'

const LoginBox = ({name})=>{
	console.log(name) // props값을 확인.. 뒤에 app.jsx에서 확인가능
	const (isLogin, setIslogin) = useState(false) //return값 array (a,b)
    //a에는 초기값이 들어감(상태값)
    //b에는 상태를 바꿀 함수
    
	return (
    	<div>
        	<button onClick={()=>{setIsLogin(!
isLogin)}}> {isLogin ? 'logout':'login'} </button> </div> ) } export default LoginBox

원래 함수형 컴포넌트는 상태를 관리할 수 없다는 단점이 있었지만 React 16.8부터는 React!
통합 후크 API를 관리할 수 있습니다!

const (state, setState) = useState(initialState);

초기 렌더링 중에 반환되는 상태는 첫 번째 인수로 전달된 initialState와 동일합니다.

setState 함수는 상태를 업데이트하는 데 사용됩니다.

<button onClick{()=>{}}></button>

여기서 콜백 함수로 래핑된 이유를 알아야 합니다.

onClick{setIsLogin(!
isLogin)}이 다음과 같은 함수로 래핑하지 않고 실행될 때

조건이 무한정 반복되는 상황에 직면하게 됩니다.

그 이유는 onClick의 인수 값으로 함수 값을 받기 때문입니다.

이벤트가 발생하면 함수를 호출해야 하는데 함수가 호출되자마자 상태가 바뀌고 상태가 바뀌면 LoginBox 함수가 다시 실행되고 다시 상태가 바뀌면 다시 렌더링을 재개하는 식이다.

무한 반복합니다.

따라서 콜백 함수로 래핑해야 합니다.

const handleLogin = ()=>{
	setIsLogin(!
isLogin) } <button onClick={handleLogin}></button>

이것도 가능합니다.

클래스 구성 요소로도 구현하려고 합니다.

import React, {Component} from 'react'

class LoginBox extends React.Component{

	state:{
    	isLogin:false,
    }
    
    handleLogin(){
    	this.setState({
        	isLogin: !
this.state.isLogin }) } render(){ return ( <div> <button onClick={()=>{this.handleLogin()}}> {this.state.isLogin ? 'logout' : 'login'} </button> </div> ) } } export default LoginBox

굳이 사용하지 않아도 되는 기능성 컴포넌트가 더 편리함은 확실히!

2.카운터

/src/pages/counter.jsx

import React, {useState} from 'react'

const Conunter = ()=>{

	const (count, setCount) = useState(0) //초기값은 0으로 시작
    
    const increment = ()=>{
    	setCount(count+1)
    } //increment 호출 시 현재상태에서 +1
    
    const decrement = ()=>{
    	setCount(count-1)
    } //decrement 호출 시 현재상태에서 -1

	return (
    	<div>
        	<h1>Counter: {count}</h1>
            <button onClick:{increment}> + </button>
            <button onClick:{decrement}> - </button>
        </div>
    )
}

export default Counter

3. Axios로 강아지 사진 가져오기.

먼저 개 이미지를 처음 로드하기 전에 “loading”이라는 문자열을 표시합니다.

업데이트할 때 이미지가 렌더링되기 전에 문자열 “loading”도 표시됩니다.

/src/pages/dog.jsx

import React, {useState, useEffect} from 'react'
import axios from 'axios'

const Dog = ()=>{
	
const (loading, setLoading) = useState(true)
const (dog, setDog) = useState('')

const getDogImage = async () => {
	const response = await axios.get('https://dog.ceo/api/breeds/image/random')
    setDog(response.data.message)
    setLoadding(false)
}

useEffect(()={
	getDogImage()
},()) //프로미스 객체를 관리하지 않는다.

두번째 인자값이 없기 때문에 class문법의 componentDidMount랑 동일하다.

console.log('component 재실행!
') //처음 랜더 됐을 때, 새로고침 시 왜 2번찍히는지를 알아야한다.

(함수가 두번 실행됐기때문) return ( <div> { loading ? 'loading' : <img src={dog} /> } <button onClick={getDogImage} disabled={loading && 'disabled'}> //disabled는 버튼비활성화옵션, 새로고침 </button> </div> ) } export default Dog

최초 렌더링 시 코드 실행 순서는 다음과 같습니다.

1. 송곳니 구성 요소 호출

2. 상태 로딩 및 개는 useState Hook을 통해 초기 값 true 및 ”로 설정됩니다.

후크는 3.useEffect를 실행하고 두 번째 인수는 빈 배열이기 때문에 처음 마운트될 때 한 번만 실행됩니다.

4. 브라우저 콘솔 창에서 “구성 요소를 다시 실행하십시오!
” 찍혀있다

5. 반환 문이 렌더링됩니다.

6. getDogImage 함수가 호출되면 로딩 상태가 true로 설정됩니다.

7. Axios를 사용하여 Dog Image API에서 데이터를 추출합니다.

8. 가져온 데이터에서 이미지 URL을 추출하고 setDog로 강아지 상태를 변경합니다.

9. 로드 상태를 false로 설정합니다.

10. 컴포넌트가 다시 렌더링되는 동안 브라우저 콘솔 창에 “Run component again!
”이 표시됩니다.

11. 강아지 사진이 화면에 표시됩니다.

기능적 구성 요소의 경우 상태가 변경되면 기능 자체가 다시 실행된다는 점에 유의해야 합니다!

// app.jsx

import React,{Component} from 'react'
import LoginBox from './pages/login'
import Counter from './pages/counter'
import Dog from './pages/dog'

export const App = () => {
	return (
    	<div>
        	Hello Server
            <LoginBox name="jung" /> //이런식으로 props값을 넘겨줄 수 있다!
<Counter /> <Dog /> </div> ) }
//index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import {App} from './app.jsx'

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

번들링 전에 package.json에 “scripts”:{“start”:”webpack server –open –hot”}를 넣으면

//shell
$ npm run start

명령을 작성할 때


실행하는 동안 브라우저 화면이 자동으로 켜집니다!