컨트롤드 인풋 vs 언컨트롤드 인풋

컨트롤드 인풋 : state로 만들어진 value, 해당 value를 변경할 수 있는 onChange(setState)

언컨트롤드 인풋 : value, onChange가 없는 것 (원시적인 인풋 형태)

  --> <input type='text', ref={inputRef} defaultValue="하이" />

(언컨트롤드 인풋에 value를 넣는건 컨트롤드 인풋으로 간주될 수 있기 때문에 언컨트롤드 인풋에서 기본값을 넣으려면 defalutValue를 사용해야한다.)

쉽게 말해서 input의 value가 onSubmit에서만 동작하는 경우 unControlledInput을 사용해도 된다.

 

컨트롤드 인풋을 사용할 때는?

예를 들면 아래와 같은 경우임.

 

1. 비밀번호 체크할 때 valid해서 밑에 빨간줄 뜨게 해야한다. (dynamic inputs)

2. 비밀번호 체크할 때 조건에 안맞으면 submit 불가능하도록 해야한다. (conditionally disabling submit button)

3. 비밀번호 검증하는 것

4. 비밀번호 형식 강제하는 것

뭐 등등 많은데 사실 몰라도 되고 그냥 컨트롤드 인풋만 사용하면 된다고 하심.

//필요로 하는 패키지나 라이브러리 불러오기
const React = require('react');
const {useState, useRef} = React;


const WordRelayHooks = () => {
    const [word, setWord] = useState('제로초');
    const [value, setValue] = useState('');
    const [result, setResult] = useState('');
    const inputRef = useRef(null);

    const onChange = e => {
        const value = e.target.value;
        setValue((prev)=>value);
    }
    const onSubmit = e => {
        e.preventDefault();
        const lastChar = word[word.length-1];
        const input = value;
        if(lastChar === input[0]){
            setResult('딩동댕');
            setWord((prev)=>input);
            setValue((prev)=>'');
        }else{
            setResult('땡');
            setValue('');
        }
        inputRef.current.focus();
    }

    return (
        <>
            <div>{word}</div>
            <form onSubmit={onSubmit}>
                <input ref={inputRef} type='text' onChange={onChange} value={value}/>
                <button>입력</button>
            </form>
            <div>{result}</div>
        </>
    );

}

//쪼갠 파일에서 쓰는 컴포넌트를 밖에서도 사용할 수 있게 해주는 것. (이것이 노드의 모듈 시스템)
module.exports = WordRelayHooks;

WordRelayHooks.jsx

 

const React = require('react');
const ReactDom = require('react-dom');
const WordRelay = require('./WordRelay'); //module.export를 했기 때문에 require로 가져올 수 있다.
const WordRelayHooks = require('./WordRelayHooks');

//ReactDom.render(<WordRelay/>, document.querySelector('#root'));
ReactDom.render(<WordRelayHooks/>, document.querySelector('#root'));

Client.jsx

코드를 바꿀 때마다 webpack 명령어로 리빌드 하는 것이 매우 귀찮은 일이고, 실수를 유발할 포인트가 매우 크다.

그래서 자동으로 리빌드 되는 방법을 알려주는 강의임.

 

1. 패키지 설치

npm i -D react-refresh 

npm i -D @pmmmwh/react-refresh-webpack-plugin

npm i -D webpack-dev-server //개발용 서버

 

2. package.json 변경

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

package.json에서 먼저 설치한 패키지들이 잘 설치되었는지 devDependencies를 확인 후 script의 dev 부분을 저렇게 바꿔주자.

webpack serve --env development

 

3. webpack-config.js 변경

3-1. 패키지 require

받았던 패키지 중에 아래 패키지를 require 해준다.

const RefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

 

3-2. webpack plugins 추가

가져온 패키지를 plugins 부분에 넣어주면 장착완료 (plugins에 넣어준 패키지들은 빌드 될 때마다 해당 부분이 실행된다고 생각하면 된다.)

plugins: [//webpack에 대한 plugins (바벨의 plugins와 다르다!)
    new webpack.LoaderOptionsPlugin({debug: true}), //Loader = module,rules 의 options에 debug: true를 넣어주는 것이다.
    new RefreshWebpackPlugin()
],

 

3-3. babel loader plugins 추가

또 바벨로더에도 플러그인을 넣어줘야한다.

('react-refresh/babel', //바벨이 최신 문법을 예전 문법으로 트랜스파일할 떄 핫리로드 기능도 추가해줌.)

//webpack과 연결할 모듈들을 적시한다.
module: {
    rules:[{
        test: /\.jsx?/,
        loader: 'babel-loader',
        options:{ //바벨로더의 옵션
            presets:[['@babel/preset-env',{  //예전 브라우저 지원 문법으로 변경해주는 프리셋
                targets:{   //@babel/preset-env 프리셋에 대한 옵션
                    browsers: ['> 5% in KR','last 2 chrome versions'] // 한국에서 5% 이상, 크롬 최신 전 버전까지만 지원 (browserslist 사이트 참고)
                },
                debug: true
            }], '@babel/preset-react'],
            plugins: [
                //'@babel/plugin-proposal-class-properties',
                'react-refresh/babel', //바벨이 최신 문법을 예전 문법으로 트랜스파일할 떄 핫리로드 기능도 추가해줌.
            ]
        }
    }],
},

이렇게 하면 바벨이 최신 문법을 예전 문법으로 트랜스파일할 때 핫리로드 기능도 추가를 해준다.

 

3-4. 데브 서버 설정 추가

데브서버의 역할 :

1. webpack.config.js에 적어둔 대로 빌드 결과물을 설정해둔 폴더로 저장해둔다. (실제로 파일이 저장되는건 아니고 ram에 저장됨.)

2. index.html을 실행하면 저장했던 결과물을 제공해준다. 

3. hot-reload 기능도 추가했기 때문에 소스에 변경점이 생기면 저장했던 결과물도 자동으로 수정해준다.

devServer: {
    devMiddleware: { publicPath: '/dist' }, //웹팩이 빌드할때 파일을 생성해주는 경로 (RAM에 추가됨)
    static: { directory: path.resolve(__dirname) }, // static은 정적파일의 경로 (index.html 같은거)
    hot: true,
}

 

※ reload vs hot-reload 

리로드는 그냥 새로고침 (기존 데이터가 날아감)

핫리로드는 기존 데이터를 보존하고 화면만 바꿔준다.

데브서버를 추가하면 그냥 리로드는 되는데 핫 리로드는 

npm i -D react-refresh 

npm i -D @pmmmwh/react-refresh-webpack-plugin

해당 두개의 패키지를 설치해야만 한다.

 

지금까지의 webpack.config.js 전체코드

const path = require('path'); //node에 기본적으로 제공해주는 path를 쉽게 조작하기 위한 라이브러리
const webpack = require('webpack');
const RefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
    name: 'word_relay-setting', //어떤 것을 위한 웹팩 설정인지
    mode: 'development', //실서비스에서는 production
    devtool: 'eval', //빠르게
    resolve: {
        extensions: ['.js', '.jsx'] //확장자 적어놓으면 xxx.js, xxx.jsx 알아서 찾아서 빌드한다.
    },
    //여기서 부터가 제일 중요
    //entry : 입력,
    //output: 출력
    entry: {
        app:['./client'] // './WordRelay.jsx' 는 이미 client.jsx에서 불러오고 있기 때문에 굳이 써주지 않아도 된다.
    },

    //webpack과 연결할 모듈들을 적시한다.
    module: {
        rules:[{
            test: /\.jsx?/,
            loader: 'babel-loader',
            options:{ //바벨로더의 옵션
                presets:[['@babel/preset-env',{  //예전 브라우저 지원 문법으로 변경해주는 프리셋
                    targets:{   //@babel/preset-env 프리셋에 대한 옵션
                        browsers: ['> 5% in KR','last 2 chrome versions'] // 한국에서 5% 이상, 크롬 최신 전 버전까지만 지원 (browserslist 사이트 참고)
                    },
                    debug: true
                }], '@babel/preset-react'],
                plugins: [
                    //'@babel/plugin-proposal-class-properties',
                    'react-refresh/babel', //바벨이 최신 문법을 예전 문법으로 트랜스파일할 떄 핫리로드 기능도 추가해줌.
                ]
            }
        }],
    },
    plugins: [//webpack에 대한 plugins (바벨의 plugins와 다르다!)
        new webpack.LoaderOptionsPlugin({debug: true}), //Loader = module,rules 의 options에 debug: true를 넣어주는 것이다.
        new RefreshWebpackPlugin()
    ],
    output: {
        //path.join : 파라미터로 전달된 경로를 합쳐준다.
        //__dirname -> 현재 경로(lecture)
        path: path.join(__dirname, 'dist'), //C:\Users\iLovePC\Desktop\codingapple\zerocho-react-webgame\lecture 에 dist를 더해준다.
        filename: "app.js",
        publicPath: "/dist/",
    },
    devServer: {
        devMiddleware: { publicPath: '/dist' }, //웹팩이 빌드할때 파일을 생성해주는 경로 (RAM에 추가됨)
        static: { directory: path.resolve(__dirname) }, // static은 정적파일의 경로 (index.html 같은거)
        hot: true,
    }
}

+ Recent posts