개발/엘리스 AI 트랙

엘리스 AI 트랙 06주차 - React 기초 II (1/29) 🔥

Max 2021. 1. 30. 18:42
반응형

✔ 06주차. 웹 프론트엔드 I

<학습 목표>

  1. React(리액트)에 대한 가장 기본적인 개념을 학습합니다.

  2. React를 사용해 다양한 컴포넌트를 만들고 이를 조합해 하나의 App을 구현합니다.

  3. Bootstrap(부트스트랩)의 기본 개념과 여러가지 요소를 활용하여 React 웹 사이트에 적용합니다.


[01 Props]

1. 컴포넌트의 재사용
  - 코드의 재사용이 중요한 이유 : 코드 유지보수성 향상, 코드 재사용이 용이, 가독성 향상
  - 컴포넌트 합성 : 컴포넌트 안에서 다른 컴포넌트 참조가능. 

function Hello(props) {
  return <h1>Hello, {props.name}</h1>;
}

function Greeting() {
  return (
    <div>
      <Hello name="Sara" />
      <Hello name="Cahal" />
      <Hello name="Edite" />
    </div>
  );
}

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

  - 컴포넌트 추출 : 한 컴포넌트가 복잡하다면 일부를 추출해서 분리하는 것이 가독성이 좋고 코드 재사용이 용이

// 추출 전 컴포넌트
function Comment(props){
    return(
        <div>
            <div className="UserInfo"> {props.name}님의 할일 </div>
            <div className="Todo">
                <div>{props.todo.task1}</div>
                <div>{props.todo.task2}</div>
            </div>
        </div>
    );
}

// Todo 반환하는 컴포넌트
function Todo(props) {
  return (
    <div className="Todo">
      <div>{props.todo.task1}</div>
      <div>{props.todo.task2}</div>
    </div>
  );
}

// 유저 정보 반환하는 컴포넌트
function UserInfo(props) {
  return (
    <div>{props.name}님의 할일 </div>
  );
}

// 출력 컴포넌트
function Comment(props){
    return(
        <div>
          <UserInfo name={props.name}/>
          <Todo todo={props.todo}/>
        </div>
    );
}

2. Props
  - Props : 컴포넌트로 전달되는 매개변수 (=함수의 매개변수) 

 

[02 State&생명주기]

1. State
  - State : 컴포넌트 안에서 관리되는 렌더링 결과물에 영향을 주는 데이터를 갖고 있는 객체 (Props : 함수 매개변수처럼 사용 / State : 함수 내에 선언된 변수처럼 사용)

  - Props와 State 차이 : Props는 부모 컴포넌트에서 자식 컴포넌트로 전달하는 값으로 자식 컴포넌트에서는 Props를 직접 수정할 수 없지만 State는 컴포넌트 내부에서 선언하며 내부에서 관리되는 값으로 값을 변경할 수 있음
→ Props는 읽기 전용으로 수정이 불가능하고, State는 원하는 경우 수정이 가능

 

2. setState()
  - setState() : State를 변경하기 위해서 사용

 

3. 생명주기
  - 생명주기 : Life cycle. 앱이 실행되고 종료되는 과정을 특정 시점 별로 나눠둔 것.
  - React의 생명주기 : 컴포넌트가 이벤트를 다룰 수 있는 특정 시점을 말하며 마운트, 업데이트, 언마운트 상태로 구성

    ① 마운트 : 컴포넌트가 실제 DOM에 삽입되는 것

    ② 업데이트 : 컴포넌트가 변하는 것

    ④ 언마운트 : 컴포넌트가 DOM 상에서 제거되는 것
  - 생명주기 메소드

    ① constructor(): State 데이터를 초기화 하는 메소드

    render(): 클래스 컴포넌트에서 반드시 구현되어야 하는 메소드

    componentDidMount(): 컴포넌트가 마운트 된 직후 호출되는 메소드

    componentDidUpdate(): 업데이트가 진행된 직후에 호출되는 메소드

    componentWillUnmount(): 컴포넌트가 마운트 해제되어 제거되기 직전에 호출되는 메소드

[03 이벤트처리와 조건부 렌더링 및 Key 설정]

1. 이벤트 처리하기
  - 이벤트 : 유저 행동의 결과 혹은 시스템에 의해 발생되는 일. onClick, OnChange, mouseover 등 React는 HTML과 동일한 이벤트 사용가능

  - React 이벤트 특징
    ① 이벤트의 이름은 카멜(Camel) 표기법으로 기재

    ② 이벤트에 실행할 코드 전달 (X) 함수 형태의 객체를 전달 (O)

    ③ DOM요소에만 이벤트 설정 가능

  - 이벤트 작성하기

    ① function 키워드를 사용해 이벤트 함수를 작성
    ② onClick={함수명} 으로 등록한 이벤트를 호출

function ActionLink() {
  // function 키워드를 사용해 이벤트 함수를 작성
  function handleClick(e) {
    console.log('The link was clicked.');
  }

  return (
                // onClick={함수명} 으로 등록한 이벤트를 호출
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

  - 이벤트 핸들링 하기
    ① 함수로 작성하여 핸들링 하기
    ② 함수 미리 작성 후, 핸들링

 

2. 조건부 렌더링(Conditional rendering) 알아보기

  - 조건문 사용하기 : 조건문 if를 사용해 렌더링

// 로그인 한 사용자에게 보여주는 컴포넌트
function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

// 로그인하지 않은 사용자에게 보여주는 컴포넌드
function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  // 2. render 에서 받은 props 를 isLoggedIn 변수로 저장
  const isLoggedIn = props.isLoggedIn;
  // 3. isLoggedIn 변수값에 따라 보여주는 것이 다름
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // 1. Greeting 함수를 불러올때 props 로 isLoggedIn 을 함께 넘김
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);

  - element variables : react element를 변수에 저장

// 로그인 버튼 컴포넌트
function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

// 로그아웃 버튼 컴포넌트
function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

// LoginControl 이라는 state를 가진 컴포넌트
class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;

    let button = null;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <!-- Greeting 불러오면서 props 로 isLoggedIn 넘김 -> 상태 확인후 사용자/게스트 맞춰서 보여줌 -->
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

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

  - JSX로 구현하기

    ① && 연산자 사용

https://reactjs-kr.firebaseapp.com/docs/conditional-rendering.html

// && 연산자 사용

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      <!-- props 로 받은 읽지않은 메세지가 0개 이상일때 -->
      {unreadMessages.length > 0 &&
        <!-- 이 아래 문장이 출력됨, 0일때는 출력되지 않음 -->
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

    ② 3항 연산자로 조건부 렌더링 구현하기

// 3항 연산자 사용
function Check(props){
  const data = parseInt(props.num);
  return(
    <div>
      { data <= 0 ? <h2>양수가 아닙니다.</h2> : <h2>양수입니다.</h2> }
    </div>
  )
}

class InputData extends React.Component {
  state = {
    num: ''
  }
  handleChange = (e) => {
    this.setState({
      num: e.target.value
    })
  }
  render() {
    return (
      <form>
        숫자를 입력하세요: <input
          value={this.state.num}
          onChange={this.handleChange}
        />
        
        {<Check num={this.state.num}/>}
      </form>
    );
  }
}

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

3. Lists and Keys

  - List

    - 리스트 만들기

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
  <li>{numbers}</li>
);

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

    - 컴포넌트들로 구성된 리스트를 반환하는 컴포넌트 : 태그마다 유니크한 key값을 주어야 함

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

<!-- 이 코드를 실행하면, 리스트 아이템에 키를 넣어야한다는 경고가 표시됩니다. -->
<!-- “키(key)“는 요소 리스트를 만들 때 포함해야하는 특수한 문자열 속성입니다. -->

  - Key : 어떤 아이템이 바뀌었는지, 혹은 추가되었는지, 혹은 삭제되었는지를 인식할 수 있게 함. 요소에 안정적인 ID를 제공하려면 배열 내부 요소에 키를 주어야 함

    - Key를 추가하기

// 키를 선택하는 가장 좋은 방법은 리스트 아이템의 형제 중 
// 리스트 아이템을 고유하게 식별할 수 있는 문자열을 사용하는 것입니다. 
// 대부분의 경우 데이터의 ID를 키로 사용합니다.

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

// 만약 렌더링된 아이템에서 사용할 안정적인 ID가 없다면, 
// 아이템 인덱스를 키로 넣어 추후에 다시 정렬할 수도 있습니다.

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

    - key로 컴포넌트 추출하기

// 키는 주변 배열의 컨텍스트에서만 의미가 있습니다.
// 예를 들어, ListItem 컴포넌트를 추출 한 경우, ListItem 자체의 루트 <li> 요소가 아닌 
// 배열의 <ListItem /> 요소가 키를 가지고 있어야합니다.

function ListItem(props) {
  const value = props.value;
  return (
    // Wrong! There is no need to specify the key here:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

    - 키는 형제 중에서 고유한 값이어야 함 : 글로벌로 유니크할 필요는 없음. 두 다른 배열을 생성할 때 동일한 키를 사용할 수 있다.

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

  - JSX에서 map() 포함하기 : JSX는 중괄호를 이용하면 모든 표현식을 포함 할 수 있기 때문에 map() 도 인라인으로 포함시킬 수 있음

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />

      )}
    </ul>
  );
}

프론트랑 진짜 안맞는다...ㅎ 때려치고 싶음

 

※ 수업 자료의 출처는 K-Digital Training x 엘리스 인공지능 서비스 개발 기획 1기 (elice.io/) 및 리액트 공식문서 (ko.reactjs.org/) 입니다.

반응형