본문 바로가기

react

[리액트를 다루는 기술] 3장 컴포넌트

1. 클래스형 컴포넌트 

 

- 클래스형 컴포넌트의 경우 state 기능 및 라이프 사이클 기능을 사용할 수 있고, 임의 메서드를 정의할 수 있음 

- 클래스형 컴포넌트에서는 render 함수가 꼭 있어야 하고, 그 안에서 보여 주어야 할 JSX를 반환해야 함 

import { Component } from 'react';

class App extends Component {
 render() {
    const name='react';
    return <div className="react">{name}</div>;
  }
}

export default App;

 

 

2. 첫 컴포넌트 생성 

 

- 파일 만들기 -> 코드 작성하기 -> 모듈 내보내기 및 불러오기 

 

MyComopnent.js

const MyComponent = () => {
    return <div>나의 새롭고 멋진 컴포넌트</div>;
};

export default MyComponent;

 

App.js

import MyComponent from "./MyComponent";

function App() {
  return (
    <MyComponent />
  );
}

export default App;

 

 

3. props

 

- 컴포넌트 속성을 설정할 때 사용하는 요소 

- props의 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정가능 

(현 상황에서는 App 컴포넌트가 부모 컴포넌트)

 

1) JSX 내부에서 props 렌더링

 

MyComponent.js

const MyComponent = props => {
    return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};

export default MyComponent;

 

2) 컴포넌트 사용할 때 props 값 지정하기 

 

- App 컴포넌트에서 MyComponent의 props 값을 지정 

 

App.js

import MyComponent from "./MyComponent";

function App() {
  return (
    <MyComponent name="React"/>
  );
}

export default App;

 

 

3) props 기본값 설정 : defaultProps

 

MyComponet.js

const MyComponent = props => {
    return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};

MyComponent.defaultProps = {
    name: '기본 이름'
};

export default MyComponent;

 

 

 

4) 태그 사이의 내용을 보여주는 children 

 

children

- 리액트 컴포넌트를 사용할 때 컴포넌트 태그 사이의 내용을 보여주는 props

 

App.js

import MyComponent from "./MyComponent";

function App() {
  return (
    <MyComponent>리액트</MyComponent>
  );
}

export default App;

 

- MyComponent 태그 사이에 작성한 리액트라는 문자열을 MyComponent 내부에서 보여주려면 props.children 값을 보여주어야 함 

 

MyComponent.js

const MyComponent = props => {
    return <div>안녕하세요, 제 이름은 {props.name}입니다.<br />
    childeren 값은 {props.children}
    입니다.
    </div>;
};

MyComponent.defaultProps = {
    name: '기본 이름'
};

export default MyComponent;

 

 

5) 비구조화 할당 문법을 통해 props 내부 값 추출하기 

 

비구조화 할당(destructuring assignment)

 

- 객체에서 값을 추출하는 문법 

- 함수의 파라미터 부분에서도 사용 가능 

- 함수의 파라미터가 객체라면 그 값을 바로 비구조화해서 사용 

 

MyComponent.js

const MyComponent =( { name, children}) => {
    return <div>안녕하세요, 제 이름은 {name}입니다.<br />
    childeren 값은 {children}
    입니다.
    </div>;
};

MyComponent.defaultProps = {
    name: '기본 이름'
};

export default MyComponent;

 

 

6) prop Types를 통한 props 검증 

 

- 컴포넌트의 필수 props를 저장하거나 props의 타입(type)을 지정할 때는 propTypes를 사용 

- name 값은 무조건 문자열(string) 형태로 전달해야 함 

import PropTypes from 'prop-types';

const MyComponent =( { name, children}) => {
    return <div>안녕하세요, 제 이름은 {name}입니다.<br />
    childeren 값은 {children}
    입니다.
    </div>;
};

MyComponent.defaultProps = {
    name: '기본 이름'
};

MyComponent.propTypes = {
    name:PropTypes.string
};

export default MyComponent;

 

isRequired를 사용하여 필수 propTypes 설정 

 

- propTypes를 지정하지 않았을 때 경고메시지 띄어 주려면 propTypes를 지정할 떄 뒤에 isRequired를 붙여 주면 됨 

- favariteNumber라는 숫자를 필수 props로 지정

 

MyComponent.js

import PropTypes from 'prop-types';

const MyComponent =( { name, favoriteNumber, children}) => {
    return (
    <div>
    안녕하세요, 제 이름은 {name}입니다.<br />
    childeren 값은 {children}
    입니다.
    <br />
    제가 좋아하는 숫자는 {favoriteNumber}입니다.
    </div>
    );
};

MyComponent.defaultProps = {
    name: '기본 이름'
};

MyComponent.propTypes = {
    name:PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
};

export default MyComponent;

 

 

4. state

 

- 컴포넌트 내부에서 바뀔 수 있는 값

- 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있음 

- props를 바꾸려면 부모 컴포넌트에서 바꾸어 주어야 함 

 

 

1) 클래스형 컴포넌트의 state

 

Counter.js

import { Component } from 'react';

class Counter extends Component {
    constructor(props) {
        super(props);
        //state의 초깃값 설정하기 
        this.state = {
            number:0
        };
    }

    render() {
        const { number } = this.state; // state를 조회할 때는 this.state로 조회 
        return (
            <div>
                <h1>{number}</h1>
                <button 
                //onClick을 통해 버튼이 클릭되었을 때 호출할 함쑤를 지정
                onClick = {()=> {
                    //this.setState를 사용하여 state에 새로운 값을 넣을 수 있음 
                    this.setState({ number: number + 1});
                }}
            >
             +1
            </button>
            </div>
        );
    }
}
export default Counter;

- 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)을 호출해 주어야 함

- 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Componet 클래스가 지닌 생성자 함수를 호출해줌 

 

- render 함수에서 현재 state를 조회할 때는 this.state를 조회하면 됨

 

- 이밴트를 설정할 함수를 넣어 줄 때는 화살표 함수 문법을 사용하여 넣어 주어야 함 

 

 

 

state 객체 안에 여러 값이 있을 때 

 

- 현재 state 안에 fixedNumber라는 또 다른 값 추가 

- 버튼이 클릭될 때 fixedNumber값은 그대로 두고 number 값만 바꾸기 

 

Counter.js

import { Component } from 'react';

class Counter extends Component {
    constructor(props) {
        super(props);
        //state의 초깃값 설정하기 
        this.state = {
            number:0,
            fixedNumber:0
        };
    }

    render() {
        const { number, fixedNumber} = this.state; // state를 조회할 때는 this.state로 조회 
        return (
            <div>
                <h1>{number}</h1>
                <h2>바뀌지 않는 값: { fixedNumber }</h2>
                <button 
                //onClick을 통해 버튼이 클릭되었을 때 호출할 함쑤를 지정
                onClick = {()=> {
                    //this.setState를 사용하여 state에 새로운 값을 넣을 수 있음 
                    this.setState({ number: number + 1});
                }}
            >
             +1
            </button>
            </div>
        );
    }
}
export default Counter;

 

 

this.setState에 객체 대신 함수 인자 전달하기 

 

- this.setState를 사용하여 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트됨

 

- this.setState를 두 번 호출함에도 불구하고 버튼을 클릭할 때 1씩 더해짐

 -> this.setState를 사용한다고 해서 state 값이 바로 바뀌지는 않기 떄문 

 

onClick ={()=> {
    this.setState({ number: number+1 });
    this.setState({ number: this.state.number+1 });
}}

 

 

- 이에 대한 해결책은 this.setState를 사용할 떄 객체 대신에 함수를 인자로 넣어주는 것

- prevState는 기존 상태이고, props는 현재 지니고 있는 props를 가리킴

this.setState((prevState, props) => {
    return {
    	// 업데이트하고 싶은 내용
    }
})

- 화살표 함수에서 값을 바로 반환하고 싶다면 코드 블록 { }를 생략 

- 숫자가 2씩 올라감

 

Counter.js -button

 <button 
      //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정
         onClick = {()=> {
              this.setState({number: number+1});
       //함수에서 바로 객체를 반환 (코드 블록{} 생략)
               this.setState(prevState => ({
                    number: prevState.number +1
                }));
            }}
          >
           +1
     </button>

 

 

this.setState가 끝난 후 특정 작업 실행하기 

 

- setState를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백(callback)함수를 등록하여 작업을 처리할 수 있음 

 

Counter.js - button

<button 
     //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정
     onClick = {()=> {
         this.setState(
         {
           number: number+1
         },
         () => {
             console.log('방금 setState가 호출되었습니다.');
             console.log(this.state);
         }
     );     
     }}
 >
  +1
 </button>

 

 

 

 

 

2) 함수 컴포넌트에서 useState 사용하기 

 

배열 비구조화 할당 

 

- 배열 안에 들어있는 값을 쉽게 추출할 수 있도록 해주는 문법 

const array = [1,2];
const one = array[0];
const two = array[1];

//배열 비구조화 문법 사용 
const array = [1,2];
const [one, two] = array;

 

useState 사용하기 

 

- useState 함수의 인자에는 상태의 초깃값을 넣어줌 

- 함수를 호출하면 배열이 반환되는데 , 첫 번째 원소는 현재 상태이고, 두 번째 원소는 상태를 바꾸어 주는 setter 함수 

 

Say.js

import { useState } from 'react';

const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕하세요');
    const onClickLeave = () => setMessage('안녕히 가세요!');

    return (
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1>{message}</h1>
        </div>
    );
};

export default Say;

 

 

한 컴포넌트에서 useState 여러 번 사용하기 

 

Say.js

import { useState } from 'react';

const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕하세요');
    const onClickLeave = () => setMessage('안녕히 가세요!');

    const [color, setColor] = useState('black');

    return (
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1 style={{color}}>{message}</h1>
            <button style={{ color:'red'}} onClick={()=> setColor('red')}>
                빨간색
            </button>
            <button style={{ color:'green'}} onClick={()=> setColor('green')}>
                초록색
            </button>
            <button style={{ color:'blue'}} onClick={()=> setColor('blue')}>
                파란색
            </button>
        </div>
    );
};

export default Say;

 

 

5. state를 사용할 때 주의사항

 

- state의 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 함

 

- 배열이나 객체를 업데이트할 때는 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트한 후, 그 사본의 상태를 setState 혹은 useState를 통해 업데이트 해야 함

 

//객체 다루기 
const object = { a:1, b:2, c:3 };
const nextObject = { ...object, b:2}; //사본 만들어서 b 값만 덮어쓰기 

//배열 다루기 
const array =[
    { id:1, value:true },
    { id:2, value:true },
    { id:3, value:false}
];

let nextArray = array.concat({ id:4 }); //새 항목 추가 
nextArray.filter(item => item.id !==2); //id가 2인 항목 제거 
nextArray.map(item => (item.id === 1 ? {...item, value:false} : item));
//id가 1인 항목의 value를 false로 설정