45일차(2)/React(8) : 모듈화된 CSS 적용하기 / form 요소 활용
App05.js - CSS 적용
//App05.js
import { Component } from "react";
//css/custom.css로딩하기
import "./css/custom.css";
/*
[ 모듈화된 css를 사용하는 방법 ]
1.css 파일의 이름에 .module.를 추가한다
2.from과 함께 import 해서 사용한다.
*/
import styles from "./css/custom.module.css";
class App extends Component{
state={
obj:{
color:"blue",
border: "1px solid red",
backgroundColor:"yellow"
},
isYellow:false
}
render(){
const classes="box bg-yellow";
return(
<div className="container">
<h1>css 적용 예제</h1>
<button onClick={()=>{
this.setState({
obj:{
...this.state.obj,
backgroundColor:"greenyellow"
}
});
}}>배경색 바꾸기</button>
<p style={this.state.obj}>p1입니다.</p>
<div className="box bg-yellow">box</div>
{/*
jsx에서 { 중괄호 내부 }
중괄호 내부는 javascript에서 사용하는 데이터가 참조되어야 한다.
ex) number, string, object, array, function
number=>10,20
string=> "abcd", 'abcd', `abcd`
object=> { key:value }
array=> [value2,value2]
function=> ()=>{}
- 데이터를 즉석에서 만들면서 참조할수도 있고, 이미 만들어진 데이터를 참조할 수도 있다.
*/}
<div className={"box bg-pink"}>box2</div>
<div className={classes}>box3</div>
<div className={`box bg-pink`}>box4</div>
<div className={`box ${ true ? "bg-yellow" : "" }`}>box5</div>
<div className={`box ${ false ? "bg-yellow" : "" }`}>box6</div>
<div className={`box ${ true && "bg-yellow" }`}>box7</div>
<div className={`box ${ this.state.isYellow ? "bg-yellow" : "" }`} onClick={()=>{
this.setState({
isYellow:!this.state.isYellow
})
}}>box8</div>
<p className={styles["text-red"]}>p요소입니다.</p>
<p className={styles["text-bold"]}>p요소입니다.</p>
<p className={`${styles["text-red"]} ${styles["text-bold"]}`}>p요소입니다.</p>
</div>
)
}
handleCss = (ref) => {
this.pRef="green"
this.setState()
}
}
export default App;
/css/custom.module.css 파일생성
/* custom.module.css */
.text-red{
color:red;
}
.text-blue{
color:blue;
}
.text-bold{
font-weight: bold;
}
.text-big{
font-size: 2rem;
}
- 이 파일은 import해도 css가 적용되지 않는다.
- custom.module.css 로 작성하면 글로벌 영역이 아니라 local 영역에서만 적용된다. 그렇게 약속된 것..
- 리액트에서는 다양한 component 를 사용한다.
- 그렇기 때문에 각각의 component 에만 적용되는 css를 가지고 있어야 할 필요가 있다.
- 어떤 css는 특정 component 에서만 필요할 수 있다.
이런 css는 파일에 module. 을 붙여서 만든다.
- 이렇게 하면 단순히 클래스명을 적는 것만으로는 적용이 안 된다.
- 이것을 적용하려면 from 을 사용해서 import하면 된다.
import styles from "./css/custom.module.css";
<p className={styles.text-red}>p요소입니다.</p>
- styles 부분의 명칭은 자유롭게 지정 가능
↓
<p className={styles [text-red] }>p요소입니다.
- 그런데 text-red 를 js에서는 빼기로 생각한다. 이를 방지하기 위해서는 해당 내용을 [ ] 로 감싸주면 된다.
- javascript object 에서 방의 내용을 참조할 때 위와 같이도 쓸 수 있다. 이런 문법으로 참조하는 것이 필요할 때가 있다.
- 보통은 . 점을 찍어서 참조하지만 그렇게 참조할 수가 없는 경우, 그럴 때 대괄호로 ["xxx"] 으로 사용하면 참조 가능하다.
[ 모듈화된 css를 사용하는 방법 ]
1.css 파일의 이름에 .module.를 추가한다
2.from과 함께 import 해서 사용한다.
- 컴포넌트별로 자기만의 css를 사용하고 싶을 경우 파일명에 module을 넣어서 만들면 된다.
- css 파일명을 작성할 때 .module을 작성하고, 필요한 요소에서는 점을 찍어서 선택자를 써야한다. ex)
<p className={`${styles["text-red"]} ${styles["text-bold"]}`}>p요소입니다.</p>
여러개의 style을 적용하고 싶은 경우. `` 과 ${} 으로 묶어준다.
App05_ex1.js
- 모듈화된 css를 적용하는 다른 방법
//App05_ex1.js
import "./css/custom.css"
//모듈화된 css
import styles from "./css/custom.module.css";
import { Component } from "react";
//여기서 import한 cn은 function으로 생각하고 사용하면 된다.
import cn from "classnames";
import binder from "classnames/bind";
//classnames binder를 이용해서 모듈화된 css를 바인딩해서 그 참조값을 cx에 대입
const cx=binder.bind(styles);
class App extends Component{
state={
btnColor:'btn-primary',
isChecked: false
}
render(){
return(
<div className="container">
<h3>모듈화된 css 사용의 불편함 해결하기</h3>
<div className="box bg-yellow">box</div>
<div className={'box bg-yellow'}>box2</div>
{/* cn(적용할 클래스를 문자열로 나열) */}
<div className={cn('box', 'bg-yellow')}>box3</div>
{/* cn({}) object를 전달해서 true, false를 활용해서 클래스를 적용할지 말지를 결정 */}
<div className={cn({box:true, 'bg-yellow':true})}>box4</div>
<div className={cn('box', {'bg-yellow':true})}>box5</div>
<h2>동적으로 class 를 적용하는 예제</h2>
<select name="color" onChange={this.onColorChange}
value={this.state.btnColor}>
<option value="btn-primary">primary</option>
<option value="btn-info">info</option>
<option value="btn-success">success</option>
</select>
<input type="checkbox" checked={this.state.isChecked}
onChange={this.onCheckChange}/>
<br/>
<button className={cn('btn', this.state.btnColor,{'btn-lg':this.state.isChecked})}>색상이 바뀌는 버튼</button>
<h2>모듈화된 css를 좀더 편하게 사용하기</h2>
<p className={styles["text-red"]}>p1입니다.</p>
<p className={cx("text-red")}>p2입니다.</p>
<p className={cx("text-blue", "text-bold", "text-big")}>p3입니다.</p>
<p className={cx("text-blue", {"text-bold":true})}>p4입니다.</p>
</div>
)
}
onCheckChange=(e)=>{
//이벤트가 일어난 요소의 checked 값 (true or false) 를 얻어와서
const isChecked=e.target.checked;
//상태값에 반영한다.
this.setState({isChecked:isChecked});
}
//select 요소가 change 되었을때 호출되는 함수
onColorChange=(e)=>{
//이벤트가 일어난 요소의 value 값을 읽어온다.
const selectedColor=e.target.value;
//상태값을 바꿔줘서 UI 가 업데이트 되도록한다.
this.setState({btnColor:selectedColor});
}
}
export default App;
*외부 노드 페이지 사이트 : https://npmjs.com/
- classnames를 검색 : https://www.npmjs.com/package/classnames
- className을 조건부로 조인해주는 유틸리티
- 클래스를 import해서 사용하게 해준다.
- 실사용 예!
- 클래스를 편리하게 제어하고 사용하게 해주는 기능
- 명령 프롬프트에서 npm install 로 설치해본다!
- 설치되면 json 파일에 바로 classnames가 추가된 것을 볼 수 있다.
- 설치되면 이제 classnames를 import해서 사용할 수 있다.
<div className="box bg-yellow">box</div>
<div className={'box bg-yellow'}>box2</div>
<div className={cn('box', 'bg-yellow')}>box3</div>
<div className={cn({box:true, 'bg-yellow':true})}>box4</div>
<div className={cn('box', {'bg-yellow':true})}>box5</div>
box1: 클래스명을 문자열로 나열
box2: 클래스명을 javascript 영역인 {} 안에 넣어서 적용
box3: cn(적용할 클래스를 문자열로 나열)
box4: cn({}) object를 전달해서 true, false를 활용해서 클래스를 적용할지 말지를 결정
box5 : object와 문자열의 조합
- 클릭시 이벤트가 일어나는 button 요소 추가하기
- 모듈화된 css의 경우 import 해서 사용하는 것이 불편하다. 개선방안은?
- classnames의 binder 를 활용한다.
- 모듈화된 css를 binder 안에 넣어서 변수(cx)에 담아준다.
<p className={styles["text-red"]}>p1입니다.</p>
<p className={cx("text-red")}>p2입니다.</p>
<p className={cx("text-blue", "text-bold", "text-big")}>p3입니다.</p>
<p className={cx("text-blue", {"text-bold":true})}>p4입니다.</p>
p1: styles["클래스명"] 으로 사용. 기존 모듈화된 CSS를 사용하는 방식
p2: cx("클래스명") 으로 cx 상수에 바로 문자열 넣기
p3: cx("클래스명1", "클래스명2", "클래스명3") 여러개의 클래스명 적용 가능
p4: cx("클래스명1", {클래스명:T/F}) 로 cx안에 object로 값 전달
- classnames 는 import된 이름으로 사용하면 된다.(cn) classnames를 설치한 다음에 import해서 사용
- classnames 의 binder를 사용해서 styles를 넣어준다.
- 그러면 마치 cn으로 일반 클래스를 사용하듯이 cx를 사용할 수 있다.
- 여러개 나열하기에는 cx가 편하다.
App06.js
//App06.js
import { Component } from "react";
class App extends Component{
state={
msg:""
}
render(){
return(
<div className="container">
<h1>form 요소를 사용해 보기</h1>
{/* form 안에 있는 submit 버튼을 누르면 submit 이벤트가 발생한다. */}
<form onSubmit={this.handleSubmit}>
<label htmlFor="msg">메세지 입력</label>
<input type="text" id="msg" onChange={(e)=>{
this.setState({
msg:e.target.value
})
}} value={this.state.msg} />
<button type="submit">전송</button>
</form>
<p>현재 입력한 내용: {this.state.msg}</p>
</div>
);
}
//form 에 submit 이벤트가 발생하면 호출되는 함수
handleSubmit = (e) => {
e.preventDefault(); //폼 제출 막기
alert(this.state.msg+" 를 전송합니다.");
}
}
export default App;
- 보통 이런 형태로 input id와 label for 를 일치시키지만,
React에서는 이 경우 에러가 발생할 수 있다.
- 이 class 안쪽은 자바스크립트 영역으로 작성하는 것이기 때문에, for도 예약어이다.
- 그래서 for과 id를 짝을 지을 때 htmlFor 로 작성한다.
(class → className 으로 바꾸는 이유와 같다.)
onSubmit() : 폼에 submit이라는 이벤트가 일어날 때 발생시킬 이벤트를 넣어주면 된다.
handleSubmit = (e) => {
e.preventDefault(); //폼 제출 막기
}
.preventDefault()
- 폼 제출(submit)을 막을 때 사용!
- 전송시 페이지가 새로고침되는 것을 막으려면 폼 제출을 막고 ajax로 전달하는 경우가 많다.
- input에 onChange 함수를 넣고 (input 요소에 뭔가 값이 입력될 때 실행되는 함수)
{} 안에는 입력받은 값이 바로 setState 되도록 작성해주면 된다
- 입력받은 내용을 상태값(state)으로 관리하고 있다가 필요한 시점에 전송할 수 있도록 하면 된다.
App06_ex1.js
//App06_ex1.js
import { Component } from "react";
class App extends Component{
state={
id:'',
pwd:'',
isSave:false //체크박스의 체크 여부
}
//input 요소에 변화가 생겼을때 호출되는 함수
handleChange=(e)=>{
//이벤트가 일어난 폼요소의 name 속성의 value 얻어오기
const name=e.target.name; //"id" or "pwd" or "isSave"
// value 를 미리 얻어내기 (체크박스인 경우에는 체크 여부를 얻어낸다 )
const value=e.target.type === 'checkbox' ? e.target.checked : e.target.value;
//ECMA6 문법을 활용하면 아래와 같이 된다.
this.setState({
[name]:value
});
}
//폼에 submit 이벤트가 발행했을때 호출되는 함수
handleSubmit=(e)=>{
e.preventDefault();
}
render() {
return (
<div className="container">
<h1>React form 테스트</h1>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="id">아이디</label>
<input type="text" value={this.state.id} onChange={this.handleChange} className="form-control" name="id" id="id" />
</div>
<div className="form-group">
<label htmlFor="pwd">비밀번호</label>
<input type="text" value={this.state.pwd} onChange={this.handleChange} className="form-control" name="pwd" id="pwd" />
</div>
<div className="form-group">
<label>
<input onChange={this.handleChange} checked={this.state.isSave} name="isSave" type="checkbox"/> 아이디 저장
</label>
</div>
<button className="btn btn-primary" type="submit">로그인</button>
</form>
<p> 아이디 : <strong>{this.state.id}</strong></p>
<p> 비밀번호 : <strong>{this.state.pwd}</strong></p>
<p> 아이디 저장할지 여부 : <strong>{this.state.isSave.toString()}</strong></p>
</div>
);
}
}
export default App;
{num:1, name:"kim"}
- 때로는 object의 방의 이름이 변수 안에 들어 있을 수도 있다.
let a ="num"
let b="name"
{ a:1 , b: "kim" }
- a, b라는 변수를 가지고 object를 만들고자 한 것인데,
저렇게 만들면 a,b가 변수가 아니라 그냥 a,b라는 방의 이름이 되어버린다.
{ [a] : 1, [b] : "kim" }
- 위와 같이 변수 안에 있는 값을 참조해서 방을 만들고 싶은 경우 이렇게 표기할 수 있다.
- setState에서 위의 예제를 이용하고 있다.
- 현재 input 3개가 changeEvent가 일어나면 동일한 함수를 호출하게 되어있다.(handleChange)
어떻게 이를 구분하는가?
→ name=" " 의 값이 다르므로 name 값으로 구분해서 사용!
e.target.name / e.target.type
- 각각 이벤트가 일어난 타겟(e.target) 의 name 속성의 밸류, 타입 속성의 밸류를 읽어올수있다.
- type이 체크박스인 경우: 체크박스의 체크여부를 읽어오겠다
type이 체크박스가 아닌 경우: 입력한 값을 넣어주겠다 라는 뜻!
[name]:value 는 각각의 input에서 아래 3가지 값을 읽어올 수 있다.
id: banana(입력한 값)
pwd: 1234
isSave: true
- 상태값이 바로바로 관리되어 아래 p요소에 출력되는 것을 볼 수 있다!
App06_ex2.js
//App06_ex2.js
import { Component } from "react";
class App extends Component{
//폼에 submit 이벤트가 발행했을때 호출되는 함수
handleSubmit=(e)=>{
e.preventDefault();
//폼에 입력한 값을 읽어온다
const id=this.id.value;
const pwd=this.pwd.value;
const isSave=this.isSave.checked;
const info=`아이디:${id} 비밀번호:${pwd} 저장여부:${isSave}`;
this.info.innerText=info;
}
render() {
return (
<div className="container">
<h1>React form 테스트</h1>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="id">아이디</label>
<input ref={(ref)=>{this.id=ref;}} type="text" className="form-control" name="id" id="id" />
</div>
<div className="form-group">
<label htmlFor="pwd">비밀번호</label>
<input ref={(ref)=>{this.pwd=ref;}} type="text"className="form-control" name="pwd" id="pwd" />
</div>
<div className="form-group">
<label>
<input ref={(ref)=>{this.isSave=ref;}} name="isSave" type="checkbox"/> 아이디 저장
</label>
</div>
<button className="btn btn-primary" type="submit">로그인</button>
</form>
<p ref={(ref)=>{this.info=ref;}}></p>
</div>
);
}
}
export default App;
- input 요소에 입력받은 값을 읽어오는 다른 방법! 참조값 ref 를 사용했다.
- state에서 관리하던 값을 info 에 넣어서 ref로 출력한 것.
- 각각의 참조값을 필드를 만들면서 저장했다.
- this.id / this.pwd / this.isSave 라는 필드를 생성하면서 ref를 저장한 것!
- 필드에 저장한 값은 handleSubmit 함수가 실행될 때 읽어온다.
'국비교육(22-23)' 카테고리의 다른 글
46일차(2)/React(10) : import, export 활용 예제(module) (0) | 2022.12.12 |
---|---|
46일차(1)/React(9) : 함수형 컴포넌트 작성 / ajax 요청으로 DB 데이터 출력 (0) | 2022.12.12 |
45일차(1)/React(7) : React 실습예제 / CSS import해서 적용하기 (0) | 2022.12.09 |
44일차(2)/React(6) : jsx 객체 활용, setState 함수 실습 (0) | 2022.12.08 |
44일차(1)/React(5) : React 저장소 clone하기 / React 코드 리뷰 (0) | 2022.12.08 |