Learning React(7. React DOM 엘리먼트 접근)

min seung moon·2021년 8월 7일
0

Learning React

목록 보기
7/15

1. DOM 엘리먼트 접근

01. 컬러라이저 예제

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Lifecycle Methods</title>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <style>
        #container {
            padding: 50px;
            background-color: #FFF;
        }

        .colorSquare {
            box-shadow: 0px 0px 25px 0px #333;
            width: 242px;
            height: 242px;
            margin-bottom: 15px;
        }

        .colorArea input {
            padding: 10px;
            font-size: 16px;
            border: 2px solid #CCC;
        }

        .colorArea button {
            padding: 10px;
            font-size: 16px;
            margin: 10px;
            background-color: #666;
            color: #FFF;
            border: 2px solid #666;
        }

        .colorArea button:hover {
            background-color: #111;
            border-color: #111;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div id="container"></div>

    <script type="text/babel">

        class Colorizer extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    color : "",
                    bgColor : "white"
                }

                this.colorValue = this.colorValue.bind(this);
                this.setNewColor = this.setNewColor.bind(this);
            }

            colorValue(e) {
                this.setState({
                    color : e.target.value
                });
            }

            setNewColor(e) {
                this.setState({
                    bgColor : this.state.color
                });

                e.preventDefault();
            }

            render() {
                let squareStyle = {
                    backgroundColor : this.state.bgColor
                };

                return(
                    <div className = "colorArea">
                        <div style={squareStyle} className="colorSquare"></div>

                        <form onSubmit={this.setNewColor}>
                            <input onChange={this.colorValue} placeholder="Enter a color value"/>
                            <button type="submit">go</button>
                        </form>
                    </div>
                )
            }
        }

        ReactDOM.render(
            <div>
                <Colorizer />
            </div>,
            document.querySelector("#container")
        );
    </script>
</body>

</html>


02. ref와의 첫 만남

  • ref(reference)
    • 최종 HTML 엘리먼트와 jsx 사이를 연결해주는 역할
  • 아래 render 메서드는 한 무더기의 JSX를 리턴하는데, 여기에는 컬러 값을 입력한 input 엘리먼트가 포함된다
  • input 엘리먼트의 DOM에 접근하는 작업시에는 참조하려는 HTML 엘리먼트에 ref라는 속성을 설정할 수 있다
  • 우리의 관심 대상은 input 엘리먼트 이므로, 거기에 ref 속성을 추가했다
    • 현재 ref 속성 값은 비어 있다
    • 보통 현재 컴포넌트가 마운트되면 자동으로 호출될 자바스크립트 콜백 함수를 ref 속성 값으로 설정한다
  • 만약 ref 속성 값으로 단순히 DOM 엘리먼트의 참조를 저장하는 자바스크립트 함수를 지정한다면, 그 모습은 아래와 같다
    • 일단 이 컴포넌트가 마운트되면 그 다음은 쉽다
    • 컴포넌트의 안의 어디서든 self._input을 사용해 input 엘리먼트를 나타내는 HTML에 접근할 수 있다
  • 아래 익명 함수는 컴포넌트가 마운트되면 호출되며, 최종 HTML DOM 엘리먼트에 대한 참조를 인자로 받는다
  • 여기서는 이 인자를 el이라고 했지만, 어떤 이름이든 상관없다
  • 이 함수는 단순히 _input이라는 커스텀 속성에 DOM 엘리먼트의 값을 지정하는 일을 한다 또한 컴포넌트에 _input 속성을 만들기 위해 self 변수를 사용해 클로저(closure, 내부함수)를 만들었다, 여기서 this는 콜백함수가 아닌 컴포넌트를 참조한다
function(el) {
	self._input = el;
}
  • input 엘리먼트의 데이터를 전달할 때 발생하는 setNewColor라는 함수에 내용을 추가한다
    • 데이터를 전달하면 input 엘리먼트의 내용이 사라지고 focusing을 해준다
  • 화살표 함수 ver
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Lifecycle Methods</title>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <style>
        #container {
            padding: 50px;
            background-color: #FFF;
        }

        .colorSquare {
            box-shadow: 0px 0px 25px 0px #333;
            width: 242px;
            height: 242px;
            margin-bottom: 15px;
        }

        .colorArea input {
            padding: 10px;
            font-size: 16px;
            border: 2px solid #CCC;
        }

        .colorArea button {
            padding: 10px;
            font-size: 16px;
            margin: 10px;
            background-color: #666;
            color: #FFF;
            border: 2px solid #666;
        }

        .colorArea button:hover {
            background-color: #111;
            border-color: #111;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div id="container"></div>

    <script type="text/babel">

        class Colorizer extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    color : "",
                    bgColor : "white"
                }

                this.colorValue = this.colorValue.bind(this);
                this.setNewColor = this.setNewColor.bind(this);
            }

            colorValue(e) {
                this.setState({
                    color : e.target.value
                });
            }

            setNewColor(e) {
                this.setState({
                    bgColor : this.state.color
                });

                this._input.focus();
                this._input.value = "";
                e.preventDefault();
            }

            render() {
                let squareStyle = {
                    backgroundColor : this.state.bgColor
                };

                var self = this;

                return(
                    <div className = "colorArea">
                        <div style={squareStyle} className="colorSquare"></div>

                        <form onSubmit={this.setNewColor}>
                            <input 
                                onChange={this.colorValue}
                                ref={
                                    (el)=>self._input = el
                                }
                                placeholder="Enter a color value"
                            />
                            <button type="submit">go</button>
                        </form>
                    </div>
                )
            }
        }

        ReactDOM.render(
            <div>
                <Colorizer />
            </div>,
            document.querySelector("#container")
        );
    </script>
</body>

</html>

03. 포탈 사용하기

  • 지금까지 단일 컴포넌트든 복수 컴포넌트의 조합이든 오직 JSX가 만드는 결과로서 HTML을 다뤘다
    • 이는 부모 컴포넌트가 강제하는 DOM 계층 구조로 제한된다는 의미이다
    • 따라서 페이지의 다른 위치에 있는 DOM엘리먼트에 임의로 접근하는 일은 불가능해 보인다
    • 그런데 과연 그럴까> 사실은 JSX를 부모 컴포넌트에게만 보내게 제한돼 있지 않으면, JSX를 페이지의 어느 곳으로든 DOM 엘리먼트로 렌더링 시킬 수 있다
    • 이 신기한 기능이 포탈(portal)이다
  • 포탈의 사용 방법은 ReactDOM.render 메서드와 매우 유사하다
    • 즉 렌더링할 JSX를 지정하고 렌더링해 보낼 대상 DOM 엘리먼트를 지정하면 된다
  • 포탈 사용을 위해서 container div 엘리먼트와 동등한 레벨의 형제로 h1 엘리먼트를 추가

  • 현재 보여주고 있는 컬러의 이름으로 h1 엘리먼트의 값이 바뀌게 해보자!
    • 핵심은 container div와 h1이 형제 엘리먼트라는 점!
  • ReactDOM.createPortal()은 두 개의 인자를 받는다
    • 첫 째는 출력될 내용의 JSX이며,
    • 둘 째는 그 JSX를 출력시킬 대상 DOM 엘리먼트이다
    • 가장 중요한 점은 h1 엘리먼트가 container div 출력하는 앱의 범위 밖에있다는 점이다
    • 즉 포탈을 사용함으로써 부모와 자식으로 이뤄진 기존 계층 구조에 갇히지 않고 페이지의 어느 엘리먼트든 직접 적은이 가능하게 된다는 예기다
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Lifecycle Methods</title>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <style>
        #container {
            padding: 50px;
            background-color: #FFF;
        }

        .colorSquare {
            box-shadow: 0px 0px 25px 0px #333;
            width: 242px;
            height: 242px;
            margin-bottom: 15px;
        }

        .colorArea input {
            padding: 10px;
            font-size: 16px;
            border: 2px solid #CCC;
        }

        .colorArea button {
            padding: 10px;
            font-size: 16px;
            margin: 10px;
            background-color: #666;
            color: #FFF;
            border: 2px solid #666;
        }

        .colorArea button:hover {
            background-color: #111;
            border-color: #111;
            cursor: pointer;
        }

        #colorHeading {
            padding: 0;
            margin: 50px;
            margin-bottom: -20px;
            font-family: sans-serif;
        }
    </style>
</head>

<body>
    <h1 id="colorHeading">Colorizer</h1>

    <div id="container"></div>

    <script type="text/babel">

        class Colorizer extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    color : "",
                    bgColor : "white"
                }

                this.colorValue = this.colorValue.bind(this);
                this.setNewColor = this.setNewColor.bind(this);
            }

            colorValue(e) {
                this.setState({
                    color : e.target.value
                });
            }

            setNewColor(e) {
                this.setState({
                    bgColor : this.state.color
                });

                this._input.focus();
                this._input.value = "";
                e.preventDefault();
            }

            render() {
                let squareStyle = {
                    backgroundColor : this.state.bgColor
                };

                var self = this;

                return(
                    <div className = "colorArea">
                        <div style={squareStyle} className="colorSquare"></div>

                        <form onSubmit={this.setNewColor}>
                            <input 
                                onChange={this.colorValue}
                                ref={
                                    (el)=>self._input = el
                                }
                                placeholder="Enter a color value"
                            />
                            <button type="submit">go</button>
                        </form>
                        <ColorLabel color={this.state.bgColor} />
                    </div>
                )
            }
        }

        class ColorLabel extends React.Component {
            render() {
                return ReactDOM.createPortal(
                    ": " + this.props.color,
                    colorHeading
                );
            }
        }

        ReactDOM.render(
            <div>
                <Colorizer />
            </div>,
            document.querySelector("#container")
        );
    </script>
</body>

</html>


profile
아직까지는 코린이!

0개의 댓글

관련 채용 정보