패스트캠퍼스 한 번에 끝내는 프론트엔드 개발(Online) 강의 정리
npx create-react-app style-loaders-example
npm run eject : Webpack 설정 꺼내서 변경
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
//CRA에서 4가지 다른 방식으로 스타일 파일들을 가져다 해석하여 사용함을 알 수 있음
import './App.css';
// cssRegex
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
}),
sideEffects: true,
},
import styles from './App.module.css';
// cssModuleRegex
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
}),
},
import './App.scss';
import './App.sass';
// sassRegex
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
},
'sass-loader'
),
sideEffects: true,
},
import styles from './App.module.scss';
import styles from './App.module.sass';
// sassModuleRegex
{
test: sassModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
}
'sass-loader'
),
},
// App.js
import './App.css'; // 전역적으로 추가됨
css 파일을 import할 때 주의해야 하는 것은 스타일을 주려고 하는 클래스의 이름들이
전역적으로 오염되지 않게 하는 것이 중요함. (기계적으로 자동화되는 부분이 아니어서
팀 내부적으로 규칙을 정하고 그 규칙에 맞게 클래스를 쓰는 방법론이 생기기 시작)
.App
.App-header (.App .header)
.App-logo (.App .logo)
.App-link (.App .link)
import styles from "./App.module.css";
function App() {
return (
<div className={stlyes["App"]}>
<header className={styles["header"]}>
<img src={logo} className={styles["logo"]} alt="logo" />
</header>
<a className={styles["link"]}>link</a>
</div>
);
}
CSS Modules allows the scoping of CSS by automatically creating a unique classname of the format
[filename]\_[classname]\_\_[hash]
.
모듈 : 전역적으로 오염되지 않게 사용한다
className="App"
className={stlyes["App"]}
import styles from "./Button.module.css";
const Button = (props) =>
<button className={styles["button"]}
{...props} />;
export default Button;
import React from "react";
import styles from "./Button.module.css";
class Button extends React.Component {
state = { loading: false };
render() {
return (<button
onClick={this.startLoading}
className={this.state.loading ? `${styles["button"]}` `${styles["loading"]}`
: styles["button"]
}
{...this.props} />
);
}
startLoading = () => {
this.setState( { loading: true, });
setTimeout( () => {
this.setState({ loading: false, });
}, 1000);
};
}
.button { background:transparent; border-radius:3px; border:2px solid red; color:red; margin:0 1em; padding:0.25em 1em; font-size:20px; }
.loading { border:2px solid grey; color:grey; }
import styles from "./App.module.css";
import Button from "./components/Button"; // 추가
function App() {
return (
<div className={stlyes["App"]}>
<header className={styles["header"]}>
<img src={logo} className={styles["logo"]} alt="logo" />
</header>
// <a className={styles["link"]}>link</a>
<Button>Button</Button>
</div>
);
}
npm i classnames
import React from "react";
import styles from "./Button.module.css";
class Button extends React.Component {
state = { loading: false };
render() {
console.log(classNames("foo", "bar")); // test
console.log(classNames("foo", "bar", "baz")); // test
console.log(classNames( {foo:true}, {bar:false} )); // test
console.log(classNames(null, false, "bar", undefined, 0, 1, {baz:null}, "" )); // falsy한 값은 안 나옴
console.log(classNames(styles["button"], styles["loading"] )); // 실제 클래스값
return (<button
onClick={this.startLoading}
className={this.state.loading ? `${styles["button"]}` `${styles["loading"]}`
: styles["button"]
}
{...this.props} />
);
}
startLoading = () => {
this.setState( { loading: true, });
setTimeout( () => {
this.setState({ loading: false, });
}, 1000);
};
}
import React from "react";
import styles from "./Button.module.css";
class Button extends React.Component {
state = { loading: false };
render() {
return (<button
onClick={this.startLoading}
className={classNames(styles["button"], // classNames로 변경하기
loading: this.state.loading,
)}
{...this.props} />
);
}
startLoading = () => {
this.setState( { loading: true, });
setTimeout( () => {
this.setState({ loading: false, });
}, 1000);
};
}
https://github.com/JedWatson/classnames
var classNames = require('classnames/bind');
var styles = {
foo: 'abc',
bar: 'def',
baz: 'xyz'
};
var cx = classNames.bind(styles);
var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz"
import React from "react";
import styles from "./Button.module.css";
import classNames from 'classnames/bind'; // 추가
const cx = classNames.bind(styles) // module.css에서 가져온 styles 객체 넣기
console.log( cx('button', 'loading') )
class Button extends React.Component {
state = { loading: false };
render() {
const {loading} = this.state; // {loading} 정의
return (<button
onClick={this.startLoading}
className={cx('button', { loading } )} // 변경
{...this.props} />
);
}
startLoading = () => {
this.setState( { loading: true, });
setTimeout( () => {
this.setState({ loading: false, });
}, 1000);
};
}
Sass/Scss > CSS로 컴파일한 것이기 때문에 동일한 방식으로 작업
이어서.