props.children

html 태그를 구성할 때에는 부모 ,자식, 형제 등의 관계가 있습니다. 태그안에 다른 태그를 넣거나 여러 태그를 넣음으로서 트리구조를 형성하게 되고 각 트리구조의 관계에 따라 그렇게 부릅니다. 그렇다면 컴포넌트에서는 그러한 구조가 성립이 될까요?

성립이 됩니다. 하지만 독립된 두 컴포넌트를 자식관계에 놓으려고 할려면 React에서는 다른 방법을 사용해야 합니다. 일반적인 태그 안에 태그를 넣는 형태로서는 부모자식관계를 만들수 없습니다.

const ChangeLanguageDropDown = () => {
  return (
    <DropDown>
      <ImEarth />
    </DropDown>
  );
};

위 코드에서 <DropDown /> 이라는 커스텀 컴포넌트 안에 <ImEarth / > 라는 컴포넌트를 자식관계로 넣었습니다. 과연 해당 부분에 잘 렌더링이 될까요?

-> 아닙니다. children 이라는 예약어를 이용해서 해당부분이 children이 들어갈 자리라고 <DropDown/> 컴포넌트에 코드를 명시해야합니다.

const DropDown= (props) => {
  return (
    <div>
      {props.children}
    <div/>
  );
};

React EventListener

const root = document.getElementById('root')
root.addEventListener('click', () => {});

JS의 전통적인 방식으로 DOM에 이벤트를 추가하려면 DOM을 특정지어서 addEventListener라는 메소드로 이벤트의 종류와 콜백함수를 추가해줘야 했습니다. 하지만 React에서는 훨씬더 직관적이고 간결한 방식으로 이벤트리스너를 추가할 수 있습니다.

<div onClick={() => {}>
<div/>

on 으로 시작하는 속성은 이벤트의 종류를 나태나냅니다. click 이벤트의 이벤트 추가 리스너를 추가하려면 onClick 을 추가하면 됩니다.

이벤트 위임이나 DOM을 특정하거나 할걱정 없이 타겟이 되는 대상 DOM에 속성으로 직접 이벤트 리스너를 추가하면 됩니다.

함수는 바로 따로 만들어 이름을 붙일수도 있으며 이때 함수이름은 정해진 것은 아니지만 일반적으로 eventHandler 로 지어줍니다. clickHandler 처럼 말입니다.

중간에 이벤트를 더이상 퍼지지 않게 막으려면 e.preventDefault() 구문이 필요합니다. 하지만 전통적인 JS에서 return false 를 속성에 넣어도 같은 역할을 할수 있습니다. 하지만 이방법은 React에서는 사용할 수 없습니다.

  • JS
<form onsubmit="console.log('You clicked submit.'); return false">
  <button type="submit">Submit</button>
</form>
  • React
function Form() {
  function handleSubmit(e) {
    e.preventDefault();
    console.log('You clicked submit.');
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

this.eventHandler

추가로 컴포넌트안에 핸들러 함수를 정의하고 추가하는데 있어서 this의 정확한 사용이 필요합니다.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

위 와 같이 .bind를 써줘야하는 이유는

handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

위코드만 봤을때 thisundefined를 의미합니다.onClick={this.handleClick} 이코드 자체는 위 코드만 넘겨준다는 것입니다. 따라서 this.handleClick 함수 자체를 this.handleClick.bind(this) 로서 해당 컴포넌트의 this를 바인딩 할 필요가 있는 것입니다.

이러한 코드를 방지하기 위해서 arrow function을 이용할 수도 있습니다.

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

this.handleClick() 자체를 넘겨주게 되었는데 이것은 onClick시 handleClick 함수를 실행시키고 반환된 값을 반환하겠다는 의미입니다. 이렇게도 사용이 가능하고

class LoggingButton extends React.Component {
  // 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
  // 주의: 이 문법은 *실험적인* 문법입니다.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

handleClick을 화살표함수로 정의하면 handleClick 안에 있는 코드의 this 는 정의 되지 않았으므로 스코프체인에 따라서 LoggingButton의 this 를 가르킵니다. 따라서 바인딩을 할 필요가 없습니다.

Component 구동방식

import "./ExpenseItem.css";
export default function ExpenseItem(props) {
  let title = props.title;
  const clickHandler = () => {
    title = "wow";
    console.log(title);
  };
  return (
    <div className="expense-item" onClick={() => clickHandler()}>
      <div>{props.date.toISOString().slice(0, 10)}</div>
      <div className="expense-item__description">
        <h2>{title}</h2>
        <div className="expense-item__price">${props.amount}</div>å
      </div>
    </div>
  );
}

이렇게 title이라는 변수를 JSX에 삽입하고 클릭 핸들러 함수로 title 변수 값을 바꾸면 브라우저에서는 렌더링을 하지 않습니다. 일반적인 변수 변경만으로 리액트는 재평가를 하지 않습니다. 재평가라는 것은 렌더링을 다시하는 것입니다.

리액트는 가장 처음 루트 컴포넌트를 실행하면서 컴포넌트 트리구조를 따라 들어있는 모든 컴포넌트를 실행하며 평가합니다. 최종 결과가 나왔을 때 브라우저는 이를 렌더링합니다. 중요한 것은 React는 이러한 과정을 다신 반복하지 않습니다. 즉, 업데이트를 하려면 리액트가 컴포넌트를 재평가 해야만 합니다.

그렇다면 재평가를 유발시키려면 어떻게 해야할 까요?

컴포넌트들의 업데이트만 가능합니다. 이를 위해서 state 라는 개념이 필요합니다.

profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글