본문 바로가기
시작/TIL(Today I Learned)

230223 - React this 바인딩, Counter 만들기, list 만들기

by 백씨네 2023. 2. 23.
728x90

오늘 내가 배운 것

1. 카운터 만들기 

2. componentDidMount, state를 이용하여 loading 구현하기

3. loading 후  증감 하는 버튼 만들기

4. 배열로 들어온 데이터 렌더하는 방법 (List)

5. this 바인딩하는 방법

 

1. 카운터 만들기

 

 

+버튼을 누르면 increment 함수를 이용해서 상태를 +1 해주고, -버튼을 누르면 decrement 함수를 이용해서 상태가 -1 된다.

 

처음 랜더 했을 경우 초기값이 10이 뜨는데 어떤 순서에 의해서 10이 되는지를 알아야 한다. 실행되자마자 10으로 세팅되는 것이 아니다.

 

 

1-1. 최초 실행 순서

  1. constructor()가 실행되면서 상태의 number는 0인 상태가 된다.
  2. number가 0 인 상태로 render()가 실행된다.
  3. 이후 Count 컴포넌트가 마운트 되면서, componentDidMount()가 호출되고 setState()에 의해 number가 10으로 바뀐다.
  4. 상태가 바뀌었으므로 render()를 실행하여 this.state.number가 10이 된다.

위에 실행 순서에 의해 최소 실행 시 사용자가 보이는 화면에 10으로 보이는 것을 알고 있어야 한다.

 

 

1.2. "+"버튼 눌렀을 때 코드 실행 순서

  1. onClick에 의해 increment() 호출이 된다.
  2. state.number의 값이 변경되고, render() 실행되면서 값이 업데이트된다.
  3. componentDidUpdate() 호출이 된다.

 

2. componentDidMount, state를 이용하여 loading 창 구현하기

 

 

2-1. loading 창 코드 실행 순서

  1. constructor 함수가 실행되면서 loading은 true, number는 0 상태가 된다.
  2. 이후 render()가 실행되며 조건식에 의해 `로딩 중...`이라는 글자가 랜더 된다.
  3. render()가 실행된 후 componentDidMount()가 호출되는데, 이때 setTimeout에 의해서 setState함수가 1초 뒤에 실행된다.\
  4. 1초 뒤 setState 함수가 실행되며 loading이 false, number가 10이 된다.
  5. 이 상태로 render()가 다시 실행된다.

 

3. loading 후  증감 하는 버튼 만들기

 

최초 로딩창은 2번, 버튼 로딩은 3번

코드는 2번을 참고

 

Button 컴포넌트로 밑에 컨트롤러를 하나 더 만든다.
누르면 로딩 중이라는 문구가 뜨고 일정시간 후 로딩 중이라는 문구가 사라지면서 숫자가 바뀐 상태로 보이기 위한 버튼을 만들 예정이다.

 

3-1. 코드 실행 순서

  1. 버튼을 누르면 setLoading 함수가 호출된다.
  2. setLoading에 의해 loading이 `true`로 바뀌고, 조건식에 따라 increment와 decrement를 호출한다.
  3. 이후 render()을 호출하는데 loading이 true이기 때문에 `로딩 중..`이 보이고,
    상태가 바뀌었으므로 componentDidUpdate()가 호출된다.
  4. componentDidUpdate()는 1초 뒤 loading의 상태를 false로 바꿔준다.

 

 

4. 배열로 들어온 데이터 렌더하는 방법 (List)

 

React에서 state에 [{},{},{}..] 배열 안에 객체로 항목이 있을 경우
이를 map()를 이용해서 JSX 문법으로 변환하면 랜더를 할 수 있다.

 

    <body>
        <div id="root"></div>
        <script type="text/babel">
            class List extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        board: [
                            { id: 1, subject: "baekspace1" },
                            { id: 2, subject: "baekspace2" },
                            { id: 3, subject: "baekspace3" },
                            { id: 4, subject: "baekspace4" },
                        ],
                    }
                }

                getList(board) {
                    return this.state.board.map((v) => <li key={v.id}>{v.subject}</li>)
                }

                render() {
                    return <ul>{this.getList(this.state.board)}</ul>
                }
            }
            class App extends React.Component {
                constructor(props) {
                    super(props)
                }
                render() {
                    return (
                        <div>
                            <List />
                        </div>
                    )
                }
            }
            const root = ReactDOM.createRoot(document.querySelector("#root"))
            root.render(<App />)
        </script>
    </body>

 

 

 

 

5. this 바인딩하는 방법

함수를 호출할 때 `this`가 가리키는 객체를 지정하지 않으면 호출하는 방법에 따라 `this`가 가리키는 객체가 달라진다. 그렇기 때문에 함수를 호출할 때, `this`가 항상 같은 객체를 가리키도록 하기 위해서 바인딩을 해줘야 한다.

decrement 함수로 this 바인딩하는 방법 몇 가지를 보면

 

방법 1. 화살표 함수 이용하기

decrement = () => {
    this.setState({ number: this.state.number - 1 })
}
render () {
    return (
        <button onClick={this.decrement}> - </button>
    )
}

 

방법 2. 이벤트 핸들러 함수를 화살표 함수로 이용하기

decrement2() {
    this.setState({ number: this.state.number - 1 })
}

render () {
    return (
        <button onClick={()=>this.decrement2()}> - </button>
    )
}

 

방법 3. 생성자 함수에서 바인딩하기

constructor (props) {
    super(props)
    this.decrement3 = this.decrement3.bind(this)
}


decrement3() {
    this.setState({ number: this.state.number - 1 })
}

render () {
    return (
        <button onClick={this.decrement}> - </button>
    )
}

더보기
Counter
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
        <title>Document</title>
        <style>
            h1 {
                text-align: center;
            }
            .counter {
                display: flex;
                justify-content: center;
                flex-direction: column;
                width: 150px;
                margin: 0 auto;
            }
            h2 {
                text-align: center;
            }
            button {
                width: 50px;
                height: 30px;
                margin: 0 10px;
                font-size: 25px;
            }
        </style>
    </head>
    <body>
        <h1>카운터 만들기</h1>
        <div id="root"></div>
        <script type="text/babel">
            class Button extends React.Component {
                constructor(props) {
                    super(props)
                }
                render() {
                    return (
                        <div>
                            <button onClick={this.props.setLoading}>+</button>
                            <button onClick={this.props.setLoading}>-</button>
                        </div>
                    )
                }
            }
            class Count extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        number: 0,
                        loading: true,
                    }
                }
                componentDidMount() {
                    setTimeout(() => {
                        this.setState({ number: 10, loading: false })
                    }, 1000)
                }
                componentDidUpdate() {
                    if (this.state.loading === true) {
                        setTimeout(() => {
                            this.setState({ loading: false })
                        }, 1000)
                    }
                }

                setLoading = (e) => {
                    this.state.loading = true
                    if (e.target.innerHTML === "+") {
                        this.increment()
                    } else {
                        this.decrement()
                    }
                }

                increment = () => {
                    this.setState({ number: this.state.number + 1 })
                }
                decrement = () => {
                    this.setState({ number: this.state.number - 1 })
                }
                render() {
                    if (this.state.loading) return <h1>로딩중..</h1>
                    return (
                        <div className="counter">
                            <h2>{this.state.number}</h2>
                            <div className="counterBtn">
                                <button onClick={this.increment}> + </button>
                                <button onClick={this.decrement}> - </button>
                                <br />
                                <br />
                                Loadding
                                <br />
                                <br />
                                <Button setLoading={this.setLoading} />
                            </div>
                        </div>
                    )
                }
            }
            class App extends React.Component {
                constructor(props) {
                    super(props)
                }
                render() {
                    return (
                        <div>
                            <Count />
                        </div>
                    )
                }
            }
            const root = ReactDOM.createRoot(document.querySelector("#root"))
            root.render(<App />)
        </script>
    </body>
</html>

 

 

List
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
        <title>Document</title>
    </head>
    <body>
        <div id="root"></div>
        <script type="text/babel">
            class List extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        board: [
                            { id: 1, subject: "baekspace1" },
                            { id: 2, subject: "baekspace2" },
                            { id: 3, subject: "baekspace3" },
                            { id: 4, subject: "baekspace4" },
                        ],
                    }
                }

                getList(board) {
                    return this.state.board.map((v) => <li key={v.id}>{v.subject}</li>)
                }

                render() {
                    return <ul>{this.getList(this.state.board)}</ul>
                }
            }
            class App extends React.Component {
                constructor(props) {
                    super(props)
                }
                render() {
                    return (
                        <div>
                            <List />
                        </div>
                    )
                }
            }
            const root = ReactDOM.createRoot(document.querySelector("#root"))
            root.render(<App />)
        </script>
    </body>
</html>

 

 

 


 

 
반응형

댓글