국비교육(22-23)

45일차(1)/React(7) : React 실습예제 / CSS import해서 적용하기

서리/Seori 2022. 12. 9. 18:21

45일차(1)/React(7) : React 실습예제 / CSS import해서 적용하기

 

 

App04_ex2.js (최종)

- 체크하면 아래 선택한 목록이 추가되도록 하기!

//App04_ex2.js

import { Component } from "react";

class App extends Component{
    state={
        selectedList:[]
    }
    //선택한 메뉴를 출력할 데이터를 담을 배열 (처음엔 선택한게 없어서 비어 있다)
    selected=[];

    render(){
        let menu=[
            {id:1, name:"김밥"},
            {id:2, name:"라면"},
            {id:3, name:"떡볶이"},
            {id:4, name:"만두"},
            {id:5, name:"우동"}
        ];
        
        //data 를 이용해서 UI를 만들어내기 (만들어낸 UI는 배열에 저장된 상태로 리턴된다)
        const newArray=menu.map((item)=>{
            //item 은 {id:x, name:x} 형태의 object 이다.
            return <label key={item.id}><input type="checkbox" onChange={(e)=>{
                //체크 박스를 체크하거나 해제하면 호출되는 함수 

                //만일 체크 했다면
                if(e.target.checked){
                    //필드에 선언된 selected 배열에 item 추가 
                    this.selected.push(item);
                }else{//체크를 해제 했다면
                    //삭제할 item 이 몇번째 index 에 있는지 찾아서 
                    const index=this.selected.indexOf(item);
                    //필드에 선언된 selected 배열에서 해당 인덱스 삭제
                    this.selected.splice(index, 1);
                }
                //state 를 변화 시켜서 UI 가 업데이트 되게 한다. 
                this.setState({
                    selectedList:this.selected.map( item => <li key={item.id}>{item.name}</li>)
                });
            }}/> {item.name} </label>;
        });            

        return(
            <div className="container">
                <h3>먹고싶은 분식 메뉴를 체크하세요.</h3>
                {newArray}                 
                <h3>선택된 메뉴 목록입니다.</h3>
                <ul>
                    {this.state.selectedList}
                </ul>
            </div>
            
        )
    }
    
}

export default App;

 

- 이 예제에서는 새로운 배열을 얻어낼 필요가 없어서, filter를 사용하지 않는다.

- indexOf() 를 사용해서 개별 값의 인덱스를 얻어내서 인덱스를 사용해서 추가하고 삭제한다.

- selected=[]; 배열은 state로 관리할 필요가 없어서 selected 라는 필드로 만들었다.

 아래에서 this.selected로 참조한다.

 

 

- jsx 객체가 들어있는 UI

- {} 안에 넣어주는 것만으로도 화면에 나타난다.

 

 

- { } 안에 배열을 참조하는 것만으로도 배열이 알아서 출력된다.

 

- onChange: 체크박스에 체크/해제하면 이벤트가 발생하도록 이벤트 걸어두기

 

 

[ 순수 javascript ]

1) <input type="checkbox" onchange="changed()">

   function changed(){}

- change 이벤트가 일어나면 아래 함수가 호출됨!

 

2) document.querySelector().addEventListener("change",function(){ });

- 문서 객체의 참조값을 얻어와서 이벤트리스너로 호출

 

[ React ]

<input type="checkbox" onChange={()=>{}} />

<input type="checkbox" onChange={this.handleChange } /> 

handleChange= ()=>{ }

- change 이벤트가 일어나면 onChange={ } 안의 함수가 호출된다!

- 이미 만들어진 함수를 호출하는 것도 가능

 

- onFocus onBlur onSubmit onMouseDown 등등..

 특정 요소에 어떤 이벤트가 발생하면 호출하도록 이벤트를 걸어놓을 수 있다.

 

- 함수가 길어서 헷갈리지만 함수가 빠져 있으면 이런 모양이다.

 

const newArray=menu.map((item)=>{            
    return <label key={item.id}><input type="checkbox" onChange={(e)=>{
        //체크 박스를 체크하거나 해제하면 호출되는 함수 
        if(e.target.checked){            
            this.selected.push(item);
        }else{            
            const index=this.selected.indexOf(item);
            this.selected.splice(index, 1);
        }
        this.setState({
            selectedList:this.selected.map( item => <li key={item.id}>{item.name}</li>)
        });
    }}/> {item.name} </label>;
});

- map 함수로 UI 를 만들어서 배열에 넣기 전에, 이벤트리스너 함수를 등록

- 함수를 호출하면서 이벤트리스너를 즉석에서 등록한 것과 같다.

 

- map 함수는 5개가 만들어진다. 하나를 만들어서 공유하는 것이 아니라 5개 만들어짐 (return이 5번!) 

- 이 함수가 만들어지는 시점마다 아이템은 각자 다를 것이다.

  ex) 1)김밥 2)라면 3)떡볶이, ...

 

- 이 함수 안에서 item이라는것은 코딩 시점에는 무엇을 가리킬 것인지 알 수 없다.

- 이 item이 무엇인지는 이벤트가 일어났을 때 결정된다. 사용자가 클릭하면 그때 item이 되는 것!

 

- 이 함수가 5개 만들어져 있는데, 그 함수에서 각각 item은 자신의 고유한 것을 가리키고 있다.

 

 

- 함수가 실행되면 이벤트객체 e가 전달된다. 이 객체는 리액트가 넣어준다.

- 체크되었을 때 필드의 빈 배열에 push로 아이템을 넣어준다.

 

this.selected.push()

- this.selected : 변화가 일어날 주체를 이 배열로 지정하는 것 

- push() : 배열에 값 추가하는 함수

 

- 현재 아이템의 인덱스 값이 무엇인지 알아내서 몇번째 인덱스에 있는지를 리턴해주기 (indexOf로 찾을 수 있다)

- 찾은 인덱스 값으로 splice(삭제) 해주기!

 

- e.target.checked 의 체크 상태에 따라서 if~else 문으로 분기하여 <li>를 생성/삭제 한다.

 

- map 함수를 사용해서 <li>가 여러개 들어있는 UI를 만들어준다.

 

- <li>가 여러개 들어있는 배열로 setState() 하는 것이다. (상태값 재설정)

- state의 상태가 바뀌면 아래 return의 UI에 자동 업데이트된다.

 


 

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;

 

const obj={
            color:"blue",
            backgroundColor:"yellow"
}
return(
    <div>
        <h1>css 적용 예제</h1>
        <p style={obj}>p1입니다.</p>
    </div>
)

- object를 이용해서 css를 적용하고 싶다면? p style={obj} 로 적용

 

 

- obj 의 값이 계속 바뀌어야 한다. → state 로 관리하기!

 

- 이렇게 state 에 넣어두고 this.state.obj 로 적용해도 css가 제대로 잘 적용된다

- 검사에서 확인해보면 inline css로 들어가 있다.

 

- 클릭했을 때 this를 새로운 obj으로 바꾸려면 onClick 함수 안에 setState가 들어가야 한다.

 

- css의 background-color가 js문법에서는 backgroundColor(카멜 케이스) 로 사용된다는 것을 기억하기!

 

 

- obj 라는 방에 들어가 있는 배경색을 blue로 하고 setState 하면?

→ 기존에 있는 값을 다 없애고 새 값으로 덮어쓴다.

   배경색 이외의 서식도(테두리, 글자색) 전부 없애 버린다.

 

- 하지만 기존의 값은 남기면서 덮어쓰고 싶다면? → ... 을 사용한다.

 

- 두 개는 같은 것이다. 기존 배열 안에 있는 데이터를 쫙 펼쳐놓고 추가한다고 생각하면 된다.

 

 

- ... 은 object 에서도 사용 가능하다.

- 기존의 object가 ...mem 안에 펼쳐지고, 추가한 내용이 추가되는 것이다.

 

 

- mem3 와 같이 방의 이름은 같고 value 값이 다르면 내용을 추가하는 것이 아니라 덮어 쓴 결과가 나온다.

- 해당 object 안에 들어있는 것을 펼쳐놓고, 특정 키 값에 있는 내용을 override 하는 것

 

- obj 의 현재 state를 쫙 펼쳐놓고, 그 안에서 배경색만 바꾸는 것

- obj도 object 이기 때문에,

  { ...this.state.obj, backgroundColor:"green" } 은 { key1:val1, key2:val2 } 형태로 작성된 것이다.(주의!)

- object를 잘 작성하도록 연습!

 

- 배경색만 바뀌고 나머지 서식은 그대로 유지됨!

 


 

src에 css폴더만들기 - custom.css 생성

/* css/custom.css */

.box{
    width: 100px;
    height: 100px;
    border: 1px solid red;
}

.bg-yellow{
    background-color: yellow;    
}

.bg-pink{
    background-color: pink;
}

 

import "./css/custom.css"; 

- import만 해도 외부 파일이 불러와져서 알아서 적용됨

- 이 경우 inline으로 적용된 것은 아니다. 검사에서 확인해보면 <style>이 따로 있다.

 

- className을 javascript {} 를 활용해서 전달할 수도 있다.

- {} 안에 문자열을 직접 작성해도 되고, 이미 만들어진 문자열을 참고해도 된다.

  백틱 `` 을 사용해서 문자를 넣어도 된다.

ex) box1 : 문자열을 직접 작성한 것

      box2 : 이미 만들어진 데이터를 문자열로 전달한 것

      box3 : 문자열을 변수에 담아서 그 변수를 참조한 것

 

- 지금은 고정된 무언가가 들어가 있지만 저 클래스를 동적으로 움직이려면?

→ add class와 remove class를 react에서는 어떻게 하는지?

 

- 적용할 요소를 지정해서 xxx.add.class 해도 되지만, { } 를 사용해볼 수 있다.

 

- 3항연산자, && 으로 className 입력하기

 

- `` (백틱) 안에 javascript 를 넣으려면 ${ } 안에 넣어주면 된다.

 

- 위의 true/false 자리에 상태값(state)를 넣으면 동적으로 변화시킬 수도 있다!

- div 클릭시에 T/F 를 변환시킬 수 있는 함수를 넣어주기

 

this.setState({ isYellow : ! this.state.isYellow });

- T→F F→T 로 바꿀 수 있는 함수. 현재 state 값을 읽어내서 반전시키면 된다!

 

- box8 은 클릭시 색깔이 바뀌는 동적인 class를 가진 div가 된다.

 

- jsx에서 { } 는 뭔가를 참조하는 데 쓰는 javascript 영역인 것을 기억하기!