mjeongriver
article thumbnail
Published 2023. 1. 16. 18:12
day66-react TIL/React

1. state

- 리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미합니다

- state가 체인지 되면 변화를 감지하여 리렌더링을 수행합니다.

- 클래스 vs 함수형 컴포넌트에서 사용하는 방법이 다릅니다.

- 함수형 컴포넌트에서는 훅 Hook개념을 이용해서 더욱 쉽게 사용 가능 합니다.

 

* 나의 첫번째 훅

- useState(초기값) 

- useState() : 배열 반환 

- 첫번째 배열의 요소에는 현재 값을, 두번째 요소는 상태를 변경하는 (setter)-function을 반환합니다

const [data, setData] = useState('초기값')

- state는 어떤 타입이던 상관 없습니다. (str, number, object)

- state는 여러개 일 수도 있습니다.

- state는 직접 수정하면 안 됩니다. setter를 사용하세요!

const StateComponent = () => {

    const [msg, setData] = useState('초기값')

    const enter = () => setData('입장했습니다')
    const exit = () => setData('퇴장했습니다')

    return (
        <div>
            <h3>{msg}</h3>
            <button onClick={enter}>입장</button>
            <button onClick={exit}>퇴장</button>
        </div>
    )

}

 

 

<h3 style={{'color': color}}>state값: {data}</h3>
     
            <hr/>
            <button onClick={() => setColor("red")}>붉은색</button>
            <button onClick={() => setColor("blue")}>푸른색</button>
            <button onClick={() => setColor("yellow")}>그 사이 3초 그 짧은 색</button>
 
setColor로 지정한 색으로 변경되면서 h3의 색이 바뀜
 

* 예제(app.js, stateComponent.js)

import { Fragment } from "react";
import StateComponent from "./component/StateComponent"

const App = () => {
    return (
        <>
        <StateComponent/>
        </>
    )
}

export default App;
import { useState, setdata } from "react";



const StateComponent = () => {

    /* 
    p.103
    state란 컴포넌트에서 변화하는 값을 의미합니다.
    state가 변경되면 컴포넌트 리렌더링을 시킵니다.
    함수형컴포넌트에서는 useState()를 사용합니다.
    */

    //함수형 컴포넌트에서는 useState()를 사용합니다
    // 1st 
    // let data = useState('초기값');
    // console.log(data);
    // let a = data[0];
    // let b = data[1];

    //2nd
    let [data, setData] = useState("초기값");
    // console.log(data); //state값
    // console.log(setData); //state setter 함수
    
    let func = () => setData("변경")
    let enter = () => setData("입장")
    let exit = () => setData("퇴장")
    
    // state는 여러개 일 수 있습니다.
    let [color, setColor] = useState("red");

    return (
        <>
            <h3 style={{'color': color}}>state값: {data}</h3>
            <button onClick={func}>값 변경하기</button>
            <button onClick={enter}>입장</button>
            <button onClick={exit}>퇴장</button>
     
            <hr/>
            <button onClick={() => setColor("red")}>붉은색</button>
            <button onClick={() => setColor("blue")}>푸른색</button>
            <button onClick={() => setColor("yellow")}>그 사이 3초 그 짧은 색</button>
     
        </>
    )


}

export default StateComponent;

 

* StateComponentQ.js

import { useState } from "react";

const StateComponentQ = () => {
    
    //++count로 state를 직접 수정하면 안됩니다.
    const [count, setCount] = useState(0); //state, set state

    return (
        <div>
            <h3/>
            <h3>실습</h3>
            <div>카운트 : {count} </div>
            <button onClick={() => setCount(count+1)}>증가</button>
            <button onClick={() => setCount(count-1)}>감소</button>
            <button onClick={() => setCount(0)}>초기화</button>
        </div>
    )
}


export default StateComponentQ;

 

* 수정된 MyComponent3.js

import { Component } from "react";


class MyComponent3 extends Component {

/*  
    state는 생성자 안에서 초기화를 합니다.
    state의 접근은 this.state를 이용해서 접근합니다.
    state는 반드시 객체 모형이어야 합니다.

    클래스형에서 생성자를 작성할 때는 반드시 props를 받고 super를 통해서 부모 컴포넌트에 연결해야 합니다.
*/
    constructor(props){
        super(props);
        this.state = {
            a : 1,
            b: props.name //부모로부터 전달받은 name
        }
    }

    //클래스형 컴포넌트는 render 함수 안에서 return문을 작성
    render(){

        let {name} = this.props; //props
        // console.log(name);

        return(
            <>
            <hr/>
            <div>나의 클래스형 컴포넌트</div>
            state값: {this.state.a}<br/>
            state값: {this.state.b}<br/>
            </>
        )
    }
}

export default MyComponent3;

 

2. 리액트 이벤트 핸들링(p.121)

1) 이벤트 규칙

- 이벤트의 이름은 전부 카멜 표기법으로 표현됩니다.  ex) onkeyup -> onKeyUp

- 이벤트를 전달할 때는 {함수} 형태로 사용합니다.

 

2) 인풋값 핸들링 해보기

- 인풋의 값이 변화되는 이벤트 onChange 연결

- 이벤트 안 첫번째 매개변수에서 event 객체 활용하기(e.target.속성값)

- setter를 이용해서 state 변경하기

 

- useState를 하나로 관리하기(객체로 사용)

const EventComponent = () => {

    const [name, setName] = useState('');
    let handleName = (e) => { //2.event객체 활용
        setName(e.target.value); //3.state변경 (input의 value도 변경)
    }
    return (
        <div>
            <h3>리액트 이벤트 핸들링</h3>
            <input type="text" name="name" onChange={handleName} value={name}/><br/> {/*1. 이벤트연결*/}
            <h3>체인지된 결과: {name}</h3>
        </div>
    )
}

 

 

* EventComponent.js, EventComponentQ.js

import { useState } from "react";

const EventComponent = () => {

    //name을 저장할 useState
    const [name, setName] = useState('')

    //이벤트 함수의 첫번째 매개변수에 이벤트에 대한 정보를 넣어줍니다.
    const handleName = (e) => {
        // console.log(e.target.value);
        setName(e.target.value); //state 체인지
    }

    //
    const [topic, setTopic] = useState('');
    const handleTopic = (e) => {
        setTopic(e.target.value);

    }

    //클릭 이벤트
    const handleClick = (e) => {
        alert(`${name}님의 주제는 ${topic}입니다.`); //state값
        setName(''); //인풋 데이터의 초기화
        setTopic(''); //인풋 데이터의 초기화
    }

    //엔터키의 처리
    const handlePress = (e) => {
        // console.log(e);
        if(e.keyCode === 13){ //엔터값
            handleClick();
        }
    }

    return (
        <>
            <h3>리액트의 이벤트 핸들링(인풋 데이터)</h3>
            <input type="text" name="name" onChange={handleName} value={name} />
            <div>체인지 된 결과 : {name} </div>

            <input type="text" name="topic" onChange={handleTopic} onKeyUp={handlePress} value={topic} />
            <div>체인지 된 결과 : {topic} </div>

            <button type="button" onClick={handleClick}>클릭 미</button>
        </>
    )
}


export default EventComponent;
import { useState } from "react";

const EventComponentQ = () => {

    const [data, setData] = useState('메뉴를 선택하세요');

    //셀렉트 태그에서는 option 태그가 기본 value가 됩니다.
    const handleChange = (e) => {
        console.log(e.target.value);
        setData(e.target.value); //state 체인지
    }

   
    return(
       <div>
        <hr/>
        <h3>셀렉트 태그 핸들링(실습)</h3>
        <select onChange={handleChange}>
            <option>피자</option>
            <option>햄버거</option>
            <option>치킨</option>
        </select>

        <h3>결과: {data}</h3>
       </div>
    )
}

export default EventComponentQ;

* EventComponent2.js

import { useState } from "react";
import EventComponent from "./EventComponent";

const EventComponent2 = () => {

    //state를 객체로 관리
    const [data, setData] = useState({ name: '', topic: ''}) //객체

    const handleChange = (e) => {

        //객체 안에서 key를 바꾸는 방법 ["키"]: 값
        const copy = { ...data, [e.target.name]: e.target.value }; //복사해서 기존 데이터를 가져옴
        // console.log(copy);
        setData(copy); //state 변경
        console.log(copy);
    }

    /*     
    const handleTopic = (e) => {
    
            console.log(e.target.name);
            const copy = {...data, [e.target.name] : e.target.value}; //데이터 복사
            setData(copy);
        } 
        */

        const handleClick = (e) => {
            alert(`${data.name}님 할일: ${data.topic}`);
            setData({name: '', topic: ''}); //state 초기화
        }


    return (
        <>
            <h3>리액트 이벤트 핸들링(객체로)</h3>

            <input type="text" name="name" onChange={handleChange} value={data.name} />
            <h3>결과: {data.name}</h3>
            <input type="text" name="topic" onChange={handleChange} value={data.topic} />
            <h3>결과: {data.topic}</h3>
            <button type="button" onClick={handleClick}>click me!</button>
        </>
    )
}

export default EventComponent2;

 

* EventComponentQ2(내 답안, 선생님 답안)

import { useState } from "react";
import EventComponent from "./EventComponent";

const EventComponentQ2 = () => {

    //state를 객체로 관리함
    const [data, setData] = useState({ name: '', topic: ''});

    const handleChange = (e) => {

        //앞에는 data의 객체를 모두 가지고 와서 뒤에 바꾸는 방법을 통해 name 값을 입력된 값으로 변경해줌
        //객체 안에서 key를 바꾸는 방법 ["키"]: 값
        const copy = { ...data, ['name']: e.target.value}; //복사해서 기존 데이터를 가져옴
        setData(copy); //state 변경
    }

    //클릭을 하면 name값을 공백으로, result를 data.name(저장된 data의 이름값)으로 변경: 키가 같으면 내용을 덮어쓸 수 있음
    const handleClick = (e) => {
        //console.log(data.name);
        //객체를 가져와서 name만 초기화(), 수정
        const copy = {...data, ['name']: '', ['result']: data.name}
        setData(copy); //state 변경
    }

    return (
        <>
            <h3>인풋 데이터 핸들링(실습)</h3>

            <h5>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리
                힌트는? 아마도 state는 두개가 필요할 듯?
            </h5>

            <input type="text" onChange={handleChange} value={data.name} />
            <button type="button" onClick={handleClick}>추가하기
            </button>
            {/* data.name을 result에 저장했으니까 data.result를 가지고 오면 그 값이 적용됨. */}
            <h3>결과: {data.result}</h3>
            
        </>
    )

}

export default EventComponentQ2;
import { useState } from "react";
import EventComponent from "./EventComponent";

const EventComponentQ2 = () => {

    //state를 객체로 관리함
    const [data, setData] = useState(''); //인풋 데이터
    const [result, setResult] = useState(''); //결과 데이터

    const handleChange = (e) => {
        setData(e.target.value); //비동기적으로 변경
        console.log(data); //이전 값이 출력 됩니다(정상)
    }

    const handleClick = (e) => {
        setResult(data); //사용자가 입력한 값으로 변경
        setData(''); //인풋 데이터는 공백으로 변경
    }

    return (
        <>
            <h3>인풋 데이터 핸들링(실습)</h3>
            <pre>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</pre>
            <pre>힌트는? 아마도 state는 두개가 필요할 듯? </pre>
            
            <input type="text" onChange={handleChange} value={data}/>
            <button type="button" onClick={handleClick}>추가하기</button>
            
            <h3>결과: {result}</h3>
            
        </>
    )

}

export default EventComponentQ2;
import { useState } from "react";
import EventComponent from "./EventComponent";

const EventComponentQ2 = () => {

    //state를 객체로 관리
    const [form, setForm] = useState({ data: '', result: '' }); //인풋 데이터

    const handleChange = (e) => {
        //data는 사용자의 입력 값으로, result는 유지
        setForm({ data: e.target.value, result: form.result })
    }

    const handleClick = (e) => {
        //data는 '', result는 data로 변경
        setForm({ data: '', result: form.data})
    }


    return (
        <>
            <h3>인풋 데이터 핸들링(실습)</h3>
            <pre>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</pre>
            <pre>힌트는? 아마도 state는 두개가 필요할 듯? </pre>

            <input type="text" onChange={handleChange} value={form.data} />
            <button type="button" onClick={handleClick}>추가하기</button>

            {/* form의 result(객체의 값 불러올 때) */}
            <h3>결과: {form.result}</h3>

        </>
    )

}

export default EventComponentQ2;

 

3. 컴포넌트 반복

- 목록 요소들을 반복처리 할때는 map함수를 이용 합니다.

- 반복 컴포넌트에는 반드시 key props를 전달해야 합니다.

- map함수는 실행한 결과를 가지고 새로운 배열을 만들 때 사용

 

array.map(callbackFunction(currenValue, index, array), thisArg)
  • currenValue: 현재값
  • index: 현재인덱스
  • arrayt: 현재배열,
  • thisArg: callbackFunction 내에서 this로 사용될 값

10, 20, 30, 40, 50으로 return (태그 리턴도 가능합니다)

 

const IterationComponent = () => {

    const arr = [1,2,3,4,5];
    const newArr = arr.map( item => item*10 ) // => 한줄일 경우 리턴

    console.log('map으로 생롭게 만들어진 newArr', newArr)
	
    return (
    	....
    )
}

 

* IteratonComponent.js



const IterationComponent = () => {


    //1. 반복 처리
    const arr = [1, 2, 3, 4, 5];

    //es5
    // const newArr = arr.map(function(item, index, arr) {
    //     return item * 10;
    // })

    //es6 = es5와 같은 표현입니다.
    // const newArr = arr.map((item, index, arr) => item * 10);
    // console.log(newArr);

    //2. 반복 처리(태그)
    //리액트에서 반복 처리 시에 key를 태그에 작성합니다. (key는 고유한 값입니다.)
    //key는 화면에서 렌더링 할 때 변화를 감지하기 위해 참조하는 값입니다.
    const newArr = arr.map( (item, index) => <li key={index}>{item}</li> );
    console.log(newArr);

    return (
        <>
            <ul>
                {newArr}
                {/* 같은 표현입니다 */}
                {/* {arr.map( (item, index) => <li key={index}>{item}</li> )} */}
            </ul>
        </>
    )
}

export default IterationComponent;

 

- map의 콜백함수의 리턴에 반복시킬 태그를 넣습니다.

- 리액트에서 key는 배열을 렌더링 시킬때 빠르게 변화를 감지하기 위해 사용하는 속성입니다.

- key는 index대신 고유한 값을 넣어 주도록 권유 됩니다. (key를 넣지 않으면 props에러가 발생 됩니다.)

- 반복할 요소를 state에 넣고 처리하기, 버튼 클릭시 인풋state의 값을 목록state에 추가하기

1) 반복처리할 state선언
2) input state, 인풋 핸들러선언
3) 버튼 클릭시 input state의 값을 목록state에 추가

import { useState } from "react";


const IterationComponent2 = () => {

    //1. 반복처리할 데이터 state
    const data = [{id:1, topic: 'hello'},
                  {id:2, topic: 'bye'} 
                 ];
    const [list, setList] = useState(data)
    const newData = list.map( item => <li key={item.id}>{item.topic}</li> )

    //2.인풋핸들러추가
    const [inputData, setInputData] = useState('')
    const handleChange = e => {
        setInputData(e.target.value) //input데이터 state로 관리
    }

    //3. 데이터 추가시 input의 값으로 1번 데이터 수정
    const handleClick = e => {
        let obj = {id: list[list.length-1].id + 1 , topic: inputData} //추가할데이터(마지막요소의 id+1, 인풋데이터)
        let newList = list.concat(obj) //state와 추가할 데이터 합치기(배열합치기)
        setList(newList); //state업데이트
        setInputData(''); //input값 비우기
    }

    return (
        <div>
            <hr/>
            <input type="text" onChange={handleChange} value={inputData}/>
            <button onClick={handleClick}>추가하기</button>
            <ul>
                {newData}
            </ul>
        </div>
    )

}

export default IterationComponent2;

 

* IterationComponent2.js

import { useState } from "react";


const IterationComponent2 = () => {
    
    
    //1. 반복할 데이터 (state로 관리)
    const arr = [
        { id: 1, topic: 'hello' },
        { id: 2, topic: 'bye' },
        { id: 3, topic: 'see you' },
    ];
    const [list, setList] = useState(arr);
    
    //2. map 함수를 이용해서 li 태그로 생성
    const newList = list.map(item =>
        <li key={item.id} onDoubleClick={ () => 
            handleRemove(item.id)}> { /* 함수 안에서 함수 호출 */}
            {item.topic}
        </li>
    )
    
    //3.  인풋 데이터 관리(data에 값 저장)
    /* 스테이트 선언 */
    const [data, setData] = useState('');
    const handleChange = (e) => {
        setData(e.target.value);
    }
    
    //4. 추가하기 버튼 클릭시 input의 값을 list 마지막에 추가
    //list[2].id 값에 + 1 해주면 4가 됨
    const handleClick = (e) => {
        let obj = { id: list[list.length - 1].id + 1, topic: data };
        // list.push(obj); //정상 작동 불가(state 절대로 직접 변경하면 안됨)
        let newArr = list.concat(obj); //원본 리스트를 수정하지 않고, 합쳐친 새로운 리스트를 반환(리스트에 obj에 합쳐진 새로운 리스트 반환)
        setList(newArr); //state 변경
        setData(''); //사용자의 입력 값(input) 초기화   
    }
    
    //5. 삭제 기능(더블 클릭이면 삭제)
    //아래에 두면 호이스팅 때문에 화살표 함수 쓰면 오류 발생하기 때문에 위로 올려줘야 함. (화살표 함수는 익명함수기 때문에 호이스팅이 불가합니다.)
    //아니면 위에 doubleClick 옆에 그냥 함수로 넣어도 가능
    // <li key={item.id} onDoubleClick={ () => console.log(1)}>
    //이벤트 안에서 함수를 호출로 연결하는 방법을 사용함
    // onClick = { () => 함수() }


    const handleRemove = (a) => {
        // console.log(a); //키
        //id가 필요함
        //filter(리턴 값이 true, false) - 콜백의 리턴이 true인 값을 가지고 새로운 배열을 생성
        // const ex = [1,2,3,4,5].filter( (item) => item != 3)
        // console.log(ex);

        const newList = list.filter( item => item.id !== a);
        setList(newList);
    }



    return (
        <>
            <h3>목록 추가하기</h3>
            <input type="text" onChange={handleChange} value={data} />
            <button type="button" onClick={handleClick}>추가하기</button>
            <ul>
                {newList}
            </ul>
        </>
    )
}

export default IterationComponent2;

'TIL > React' 카테고리의 다른 글

day70-react  (0) 2023.01.19
day69-react  (0) 2023.01.18
day68-react  (0) 2023.01.18
day67-react  (0) 2023.01.17
day65-react  (0) 2023.01.13
profile

mjeongriver

@mjeongriver

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그