반응형

React에는 컴포넌트가 로드될 때, 업데이트 될 때 , 제거될 때 자동으로 호출되는 API 가 존재

=> React 의 Life Cycle API 

초기 생성 API

- 브라우저에 컴포넌트가 나타나기 전 호출되는 API

  • Constructor(props) : 컴포넌트 생성자 함수로 컴포넌트가 새로 만들어 질 때마다 호출
  • ComponentWillMount() : 컴포넌트가 화면에 나타나기 직전에 호출되는 API
    -> 주로 서버를 호출하는 용도로 사용되었는데 이 API를 더 필요하지 않다고 판단하여 사용하지 않게 됨 
    기존에 처리하던 부분은 constructor이나 componentDidMount에서 처리할 수 있음
  • componentDidMount() : 컴포넌트가 나타난 후 호출되는 api
    주로 , D3, masonry 처럼 DOM 을 사용하는 외부 라이브러리와 연동하거나, 데이터를 axios , fetch 등 통해 ajax 요청하거나, DOM 속성(스크롤 설정, 크기 등) 읽거나 직접 변경하는 작업 함

업데이트 API

- 로드된 컴포넌트가 props, state 변화로 인해 변경될 경우 호출되는 API 

  • componentWillReceiveProps(nextProps)  :
    자식 component가 부모 Component로 부터 새로운 props 를 받게 되었을 때 호출
    지금 사용되지 않음 -> getDerivedStateFromProps사용
  • static getDerivedStateFromProps(nextProps, prevState) :
    props로 받아온 값을 state로 동기화하는 작업을 해주어야할 경우 사용

    setState로 state 값을 설정하는 것이 아니라, 객체 형태로 state 값 리턴
    업데이트 할 값이 없다면 null 리턴
  • shouldComponentUpdate(nextProps, nextState)  :
    - 컴포넌트 최적화 작업에서 유용 
    - React는 변화가 발생한 DOM 만 찾아 변화시켜주는데 자식 Component가 직접적으로
    변하지 않았어도 부모가 Component가 리렌더링 되면 자식 컴포넌트도 다시 렌더링되며 Virtual Dom에 그려짐 
    - 기존 DOM 과 비교해서 변화가 발생했다면 실제 DOM 이 변경되고 그렇지 않다면 아무 작업도 하지 않음
    - 많은 렌더링 작업 시 부하가 생기고 기본적으로 true 값을 반환하고 우리가 조작하는 상황에 따라 false를 반환
        => render() 함수를 호출하지 않게 되고, Virtual DOM 에 리렌더링하는 작업을 막을 수 있음 
  • componentWillUpdate(nextProps, nextState) : 
    - shouldComponentUpdate에서 true가 반환되었을 때 호출
    - 주로 애니매이션 효과를 초기화하거나, 이벤트 리스너를 없애는 작업 

    - 이 함수 다음에 render 함수가 호출 (업데이트 이후 쓰이지 않음 아래 함수로 대체)
  • getSnapshotBeforeUpdate(prevProps, prevState)
    -  render 함수와 ComponentDidUpdate사이에 호출 
    - DOM 변화가 일어나기 직전의 DOM 상태를 가져오고, 여기서 그 상태 값(snapshot)을 반환해서 ComponentDidUpdate의
       3번째 매개변수로 받아 올 수 있다
    - 예 ) 현재 위치 스크롤바 유지하고 싶을 때 => 이 , api에서 현재 스크롤바 위치를 구해 그 값을 매개 변수로 반환 =>           componentDidUpdate에서 그 인자를 받아 스크롤바 위치 처리를 해주는 식 
    - render -> getShapshotBeforeUpdate -> 실제 DOM 업데이트 -> componentDidUpdate 순 진행
  • componentDidUpdate(prevProps, prevState, snapshot) : 
    - render 함수가 호출된 후 호출 
    - 이 시점에  this.props와 this.state는 변경된 상태 
    - 매개 변수로 받은 prevProps와 prevState는 말 그대로 변경 이전의 props와 state 값

제거 api

- 컴포넌트가 더 이상 사용되지 않을 경우 호출되는 api 

  • componentWillUnmount() : 
    - 주로 이벤트 제거 , setTimeout 의 clearTimeout 통한 제거 , setinterval의 clearInterval 통한 제거 작업
    - 외부 라이브러리 사용 시, 이 부분에서 해당 라이브러리의 dispose 기능 실행

src/StopWatch.js 수정 (기존 코드 + 주석 범위 안에 life cycle api 추가)

// StopWatch.js
import React, { Component } from "react";
 
class StopWatch extends Component {
  // class fields
  state = {
    sec: 0,
    buttonFlag: true,
    intervalFunction: null
  };
 
  /* Life Cycle API 영역 시작 */
  constructor(props) {
    super(props);
    console.log("constructor");
  }
 
  componentWillMount() {
    console.log("componentWillMount");
  }
 
  shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate");
    if (nextState.sec % 2 === 0) {
      console.log(`${nextState.sec} % 2 === 0`);
      return false;
    }
    return true;
  }
 
  componentWillUpdate(nextProps, nextState) {
    console.log("componentWillUpdate");
  }
 
  componentDidUpdate(prevProps, prevState) {
    console.log("componentDidUpdate");
  }
 
  /* Life Cycle API 영역 끝 */
 
  // stop watch 로직
  timer = () => {
    // 비구조화 할당 사용( { sec } 부분 )
    this.setState(({ sec }) => ({
      sec: sec + 1
    }));
  };
 
  // start 버튼 클릭
  start = () => {
    this.setState({
      sec: 0,
      buttonFlag: false,
      intervalFunction: setInterval(this.timer, 1000)
    });
  };
 
  // stop 버튼 클릭
  stop = () => {
    clearInterval(this.state.intervalFunction);
 
    this.setState({
      buttonFlag: true
    });
  };
 
  render() {
    return (
      <React.Fragment>
        <h1>Stop Watch</h1>
        <div>
          <b>{this.state.sec}</b>
          <span>초</span>
          {this.state.buttonFlag ? (
            <button onClick={this.start}>start</button>
          ) : (
            <button onClick={this.stop}>stop</button>
          )}
        </div>
      </React.Fragment>
    );
  }
}
 
export default StopWatch;

 

=> state 내의 sec가 0,2,4 즉, 짝수일 경우 컴포넌트를 변화시키지 않으므로 shouldComponentUpdate 까지만 호출
     실제 변화는 발생하지 않는다 / sec가 5 -> 6으로 변할 때 , stop 버튼을 눌러 state 안에 buttonFlag 값이 바뀌어
     마지막에 컴포넌트의 변화가 일어남

 

에러 처리 api

-render 함수 안에 에러가 발생하면, react 앱 기능이 정지  / 이 현상을 막기 위해 사용하는 api

 

  • componentDidCatch(error, info) :
    - render 함수 안에 에러가 발생 시 , 호출
    - state 에 error 이라는 변수를 생성 -> 해당 api 호출 시 setState로 error 값을 변경하여 render 함수 쪽에
       다시 에러용 UI를 보여줌
    - 주의점 : Component 자신의 render 함수에서 발생하는 에러는 잡을 수 없고, 자식 Component 내부의 render 함수에서 발생하는 에러를 잡음

src/StopWatch.js

-> ErrorMaker라는 인위적으로 에러를 생성하는 컴포넌트를 함수형 컴포넌트 형식으로 생성

    StopWatch 내부에서는 state의 인자로 error라는 값이 추가되었고 Life Cycle API 영역에서 마지막에 componentDidCatch가        추가.

     render 함수에서는 앱 중지를 방지하는 코드가 추가되었고, state의 sec가 3이 되었을 때, ErrorMaker를 생성.

// StopWatch.js
import React, { Component } from "react";
 
// Error 생성용 자식 Component
const ErrorMaker = () => {
  throw new Error("Error Occured!!");
  return <div />;
};
 
class StopWatch extends Component {
  // class fields
  state = {
    sec: 0,
    buttonFlag: true,
    intervalFunction: null,
    error: false
  };
 
  /* Life Cycle API 영역 시작 */
  constructor(props) {
    super(props);
    console.log("constructor");
  }
 
  componentWillMount() {
    console.log("componentWillMount");
  }
 
  shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate");
    if (nextState.sec % 2 === 0) {
      console.log(`${nextState.sec} % 2 === 0`);
      return false;
    }
    return true;
  }
 
  componentWillUpdate(nextProps, nextState) {
    console.log("componentWillUpdate");
  }
 
  componentDidUpdate(prevProps, prevState) {
    console.log("componentDidUpdate");
  }
 
  // render에서 에러 발생시 호출
  componentDidCatch(error, info) {
    console.log("componentDidCatch");
    this.setState({
      error: true
    });
  }
 
  /* Life Cycle API 영역 끝 */
 
  // stop watch 로직
  timer = () => {
    // 비구조화 할당 사용( { sec } 부분 )
    this.setState(({ sec }) => ({
      sec: sec + 1
    }));
  };
 
  // start 버튼 클릭
  start = () => {
    this.setState({
      sec: 0,
      buttonFlag: false,
      intervalFunction: setInterval(this.timer, 1000)
    });
  };
 
  // stop 버튼 클릭
  stop = () => {
    clearInterval(this.state.intervalFunction);
 
    this.setState({
      buttonFlag: true
    });
  };
 
  render() {
    // 다음과 같이 에러 발생시에 앱이 중지되는 것을 방지한다.
    if (this.state.error) return <h1>에러 발생!!</h1>;
 
    return (
      <React.Fragment>
        <h1>Stop Watch</h1>
        {this.state.sec === 3 && <ErrorMaker />}
        <div>
          <b>{this.state.sec}</b>
          <span>초</span>
          {this.state.buttonFlag ? (
            <button onClick={this.start}>start</button>
          ) : (
            <button onClick={this.stop}>stop</button>
          )}
        </div>
      </React.Fragment>
    );
  }
}
 
export default StopWatch;

결과는?

x 버튼 누르면 다음과 같이 에러 발생 시 정해둔 ul 가 나타남
-> 에러 발생하는 이유는 

    - 존재하지 않는 함수를 호출하려고 할 때(props로 받은 줄 알았던 함수 호출할 때)

    - 배열이나 객체를 받을 줄 알았을 때 존재하지 않을 때

 

render() {
    // 에러를 유발시키는 유형(실제로 props에서 onClick(), object, array를 받지 않았다고 가정)
    /*
        this.props.onClick();
        this.props.object.value;
        this.props.array.length;
    */
 
    // 다음과 같은 분기문을 추가하여 에러를 방지한다.
    if( !this.props.object || this.props.array || this.props.array.length === 0 ) return null;
 
    // ...
}

 혹시 누락 발생할 거 같으면 다음과 같이 defaultProps를 이용해 해당 값들을 초기화해서 사용

class Test extends Component {
    static defaultProps = {
        onClick: () => console.warning("onClick is not defined"),
        object: {},
        array: []
    }    
}

 

인용

https://dev-kani.tistory.com/11?category=849014
반응형

'Language Study > React' 카테고리의 다른 글

3. props와 state  (0) 2019.11.26
2. JSX  (0) 2019.11.26
1. 준비사항  (0) 2019.11.26
반응형

React Component에서 다루는 데이터는 props와 state

 

props

자식 Component가 생성될 때 부모 Component에서 받아온 데이터로 변경이 불가능

자식 Component에서 this라는 키워드를 통해 부모 Component로부터 받은 props를 사용할 수 있음

 

src/Card.js

// Card.js
import React, { Component } from "react";
 
class Card extends Component {
  render() {
    return (
      <React.Fragment>
        <h3>
          이름 : <b>{this.props.name}</b>
        </h3>
        <h3>
          소속 : <b>{this.props.department}</b>
        </h3>
        <h3>
          연락처 : <b>{this.props.phone}</b>
        </h3>
        <h3>
          이메일 : <b>{this.props.email}</b>
        </h3>
      </React.Fragment>
    );
  }
}
 
export default Card;

scr/App.js 수정

// App.js
import React, { Component } from "react";
import Card from "./Card";
 
class App extends Component {
  render() {
    return (
      <Card
        name="jisu"
        department="Dev"
        phone="010-1234-5678"
        email="282532@naver.com"
      />
    );
  }
}
 
export default App;

Card가 App의 자식 Component가 되는 것
이 때, 부모Component(App.js) 에서 지정한 name, department, phone, email

-> 자식Component(Card.js)로 전달되어 

Card에서 this.props.name, this.props.department, this.props.phone, this.props.email이 사용

 

<defaultProps>

- 부모 Component 가 여러 개의 공통된 자식 Component 를 사용할 경우

 -> 하지만, 자식 Component에서 공통적으로 사용되는 props와 값이 다양한 props가 있을 수 있다

- 이 경우 , 자식 Component에서 defaultPorps를 이용하여 props의 기본값을 설정해 줄 수 있음

- 기본값 : 부모 Component에서 지정해 줄 경우 지정한 값으로 지정하지 않으면 기본값으로 props가 적용

 

//Card.js

import React, { Component } from "react";
 
class Card extends Component {
  static defaultProps = {
    department : "Dev"
  };

  render() {
    return (
      <React.Fragment>
        <h3>
          이름 : <b>{this.props.name}</b>
        </h3>
        <h3>
          소속 : <b>{this.props.department}</b>
        </h3>
        <h3>
          연락처 : <b>{this.props.phone}</b>
        </h3>
        <h3>
          이메일 : <b>{this.props.email}</b>
        </h3>
      </React.Fragment>
    );
  }
}
 
export default Card;

//App.js

// App.js
import React, { Component } from "react";
import Card from "./Card";
 
class App extends Component {
  render() {
    return (
      <React.Fragment>
        {/* department 생략 */}
        <Card name="jisu" phone="010-1234-5678" email="282532@naver.com" />
        <hr />
        {/* department 포함 */}
        <Card
          name="joby"
          department="Marketing"
          phone="010-5678-9123"
          email="bob@bob.com"
        />
      </React.Fragment>
    );
  }
}
 
export default App;

<Functional Component(함수형 컴포넌트)>

- 클래스형 컴포넌트 외 다른 방법으로 컴포넌트 생성

- 단순히 props 받아오는 컴포넌트의 경우 더 간단한 문법으로 사용 가능

- 함수형 컴포넌트는 컴포넌트가 함수이기 때문에 클래스의 특성에서 지닐수 있는 static이나 this 키워드를 사용할 수 없음

-  state나 Life Cycle과 관련된 함수를 사용할 수 없습니다.

 

//Card.js => 함수의 매개변수로 props의 인자들 직접 받음 

 

// Card.js
import React from "react";
 
const Card = ({ name, department, phone, email }) => {
  return (
    <React.Fragment>
      <h3>
        이름 : <b>{name}</b>
      </h3>
      <h3>
        소속 : <b>{department}</b>
      </h3>
      <h3>
        연락처 : <b>{phone}</b>
      </h3>
      <h3>
        이메일 : <b>{email}</b>
      </h3>
    </React.Fragment>
  );
};
 
// 기본 props 지정(함수형 컴포넌트 사용시 static을 사용불가)
Card.defaultProps = {
  department: "Dev"
};
 
export default Card;

state

-  Component 내부에서 생성된 데이터로 변경이 가능

- Component 내부에 state를 class field나 constructor(props) 내부에 정의해서 사용

 

Method Binding

- 이벤트 처리할 경우 , 임의의 메소드 생성

- 이 때, 해당 메소드에서 state를 변경하기 위해 this 키워드를 사용하려면 메소드에 this를 바인딩 시켜주어야

- constructor(props) 내부에 "this.메소드명 = this.메소드명.bind(this)"를 사용하여 메소드에 this를 바인딩

=> 이 작업이 없을 경우, 이벤트가 발생 시 해당 메소드가 이벤트로 전달되는 과정에서 this와 연결이 끊어져, undefined가 됨

      하지만, this 를 메소드로 화살표 함수 표현(Arrow Function Expression)으로 만들 경우,
      this 가 풀리는 것에 대해 걱정할 필요가 없기에 method binding 명시적으로 하지 않아도 됨

 

 

setState

- 선언된 state 값을 변경하기 위해서는 무조건 this.setState를 사용 /
   React 내부에서 setState를 호출하게 되면 자동으로 Component를 리렌더링하게 설계

- 객체로 전달되는 해당 값만 state에서 변경. 전달되지 않은 값은 기존값으로 유지.
   state 내부에 객체가 존재하고 그 객체의 특정 인자만 변경하고 싶다면
  "객체1: { ..., this.state.객체1, 변경요소: 변경요소 값 }"의 다음과 같은 구조로 작성

   =>  그렇지 않으면 객체 자체를 새로 덮어 써버림

 

 전개 연산자(Spread Operator, ...)을 사용하면 기존 내용을 해당 객체에 풀어줌.

 - 이 부분은 객체의 depth가 깊어지면 상당히 복잡해지므로 immutable.js나 immer.js를 이용해서 간단화 작업을 하는게 좋음

 - 기존의 값을 토대로 새로운 값으로 변경하고 싶을 땐 "값1: this.state.값1" 이런 식으로 처리.

     =>  this.state를 사용하고 싶지않다면 setState를 화살표 함수로 만들어서 매개변수로 state나 해당 값을 넣어주면 됨.

    이 때, 해당 값을 이용할 땐 비구조화 할당(Destructuring Assignment)이라는 문법을 사용합니다.

 - render() 함수 내부의 HTML 코드에서 이벤트를 설정할 땐, camelCase로 이벤트명을 적어야 함

  - 또한 이벤트 속성의 값으로는 "함수()" 형태가 아닌 "함수명"으로

     => 그렇지 않을 경우 함수 호출이 무한 루프에 빠질수 있습니다. (렌더링 -> 함수 호출 -> setState -> 리렌더링 -> 함수 호출 -> ...)

 

src/StopWatch.js

// StopWatch.js
import React, { Component } from "react";
 
class StopWatch extends Component {
  // class fields
  state = {
    sec: 0,
    buttonFlag: true,
    intervalFunction: null
  };
 
  // stop watch 로직
  timer = () => {
    // 비구조화 할당 사용( { sec } 부분 )
    this.setState(({ sec }) => ({
      sec: sec + 1
    }));
  };
 
  // start 버튼 클릭
  start = () => {
    this.setState({
      sec: 0,
      buttonFlag: false,
      intervalFunction: setInterval(this.timer, 1000)
    });
  };
 
  // stop 버튼 클릭
  stop = () => {
    clearInterval(this.state.intervalFunction);
 
    this.setState({
      buttonFlag: true
    });
  };
 
  render() {
    return (
      <React.Fragment>
        <h1>Stop Watch</h1>
        <div>
          <b>{this.state.sec}</b>
          <span>초</span>
          {this.state.buttonFlag ? (
            <button onClick={this.start}>start</button>
          ) : (
            <button onClick={this.stop}>stop</button>
          )}
        </div>
      </React.Fragment>
    );
  }
}
 
export default StopWatch;

src/App.js

// App.js
import React, { Component } from "react";
import StopWatch from "./StopWatch";
 
class App extends Component {
  render() {
    return <StopWatch />;
  }
}
 
export default App;

 

반응형

'Language Study > React' 카테고리의 다른 글

4. Life Cycle API  (0) 2019.11.26
2. JSX  (0) 2019.11.26
1. 준비사항  (0) 2019.11.26
반응형

JavaScript xml

 

HTML 형태의 코드를 js 코드로 변환하기 위한 규칙 

- jsx에서는 태그를 닫지 않으면 오류가 발생 , 꼭 태그를 열었으면 닫아주어야 합니다.

 

- 두 개 이상의 엘리먼트는 반드시 하나의 엘리먼트로 감싸야 한다.
   div 태그로 감싸는 방법도 있지만, 스타일 중복이나 table 관련 태그가 번거롭기 때문에 React v16.2에 도입된 Fragment을 이용

   Fragement를 사용하게 되면 실제 DOM 자체는 생기지 않는다. (논리적 엘리먼트이기 때문에)

import React, { Component } from "react";
 
class App extends Component {
  render() {
    return (
      <React.Fragment>
        <h1>My name is</h1>
        <b>jisu</b>
      </React.Fragment>
    );
  }
}
 
export default App;

- jsx 내부에서 javascript의 변수나 함수를 사용하기 위해  {}를 사용

import React, { Component } from "react";
 
class App extends Component {
  render() {
    const color = "black";
 
    return <h1>Color is {color}</h1>;
  }
}
 
export default App;

-jsx 내부에서 조건문 사용시 , 삼항연산자(조건? 참 : 조건) 이나 AND 연산자(조건 &&참) 이용

 IF문은 기본적으로 사용할 수 없고, 사용하려면 IIFE(즉시 실행 함수 표현)을 사용

import React, { Component } from "react";
 
class App extends Component {
  render() {
    const lib = "react";
 
    return (
      <React.Fragment>
        {/* IIFE(즉시 실행 함수) 사용 */}
        {(() => {
          if (lib === "angular") return <h1>Angular</h1>;
          if (lib === "react") return <h1>React</h1>;
          if (lib === "vue") return <h1>Vue</h1>;
        })()}
      </React.Fragment>
    );
  }
}
 
export default App;

 

import React, { Component } from "react";
 
class App extends Component {
  render() {
    const color = "white";
    const lib = "react";
 
    return (
      <React.Fragment>
        {color === "black" ? <h1>검정색</h1> : <h1>다른색</h1>}
        {lib === "react" && <h2>리액트</h2>}
      </React.Fragment>
    );
  }
}
 
export default App;

- JSX에서 style과 className을 사용할 때 

  #styel변수로 사용할 경우 객체 형태로 생성

  #속성이름은 하이펀(-)형태로 camelcase로 바꾸어야한다
    (background-color ==> backgroundColor) 
  #또한 class 대신 className 을 사용

 

// App.css 수정
.App {
  background-color: black;
  color: magenta;
  font-size: 24px;
  font-weight: bold;
  padding: 15px;
}

import React, { Component } from "react";
import "./App.css";
 
class App extends Component {
  render() {
    const style = {
      backgroundColor: "cyan",
      color: "white",
      textDecoration: "underline"
    };
 
    return (
      <div className="App">
        <span>My Name is </span>
        <span style={style}>Kani</span>
      </div>
    );
  }
}
 
export default App;

반응형

'Language Study > React' 카테고리의 다른 글

4. Life Cycle API  (0) 2019.11.26
3. props와 state  (0) 2019.11.26
1. 준비사항  (0) 2019.11.26
반응형

정의 : 컴포넌트를 여러가지 파일로 분리하여 저장하고 JS가 아닌 JSX 라는 문법을 사용

 

- Webpack : 여러가지 분리된 파일 하나로 합쳐주는 라이브러리

- Babel : jsx를 비롯한 새로운 js 문법을 사용하기 위한 라이브러리

- Node.js : Webpack과 Babel 등 여러 라이브러리를 사용하기 위한 javascript 런타임

- Yarn : 캐싱 시스템 등 조금 더 개선된 npm(node package manager)

- Visual Studio Code : 실제 개발을 위해 필요한 에디터 (공짜)

 

 

컴포넌트 App.js 코드 분석

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

//파일에서 jsx문법 사용하려면 React 꼭 import
//Webpack을 사용하기에 logo.svg와 App.css를 이런식으로 불러옴

 

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }
}

//컴포넌트 만드는 방법 중 하나인 클래스 이용하는 방법
//클래스는 꼭 render()이 있어야하고 그 내부에서 jsx를 반환 
//return 뒤의 html 같은 코드 = jsx
	
export default App;
//작성된 컴포넌트를 다른 곳에서 불러 사용하게 할 수 있는 코드

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
//APP 컴포넌트 사용하기 위해 import
import * as serviceWorker from './serviceWorker';
 
ReactDOM.render(<App />, document.getElementById('root'));
//브라우저 상 React컴포넌트를 보여주기 위해 ReacDOM.render(렌더링 결과물, 그릴 DOM ) 함수 사용
//public/index.html 파일에 있는 id가 'root'인 DOM을 찾아 app컴포넌트를 렌더링
serviceWorker.unregister();
반응형

'Language Study > React' 카테고리의 다른 글

4. Life Cycle API  (0) 2019.11.26
3. props와 state  (0) 2019.11.26
2. JSX  (0) 2019.11.26

+ Recent posts