[React] Event, Rendering, List

MinJi·2024년 8월 13일

FrontEnd

목록 보기
5/13

React 이벤트 제어

  • camelCase를 사용한다.

  • JSX에 문자열 대신 함수를 전달한다.

    <button onClick={activateLasers}>
      Activate Lasers
    </button>
  • false 리턴을 사용할 수 없으므로 preventDefault를 호출해야 한다.

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }

이벤트 핸들러

  • 주로 컴포넌트 내부에서 정의된다.
  • handle로 시작하고 그 뒤에 이벤트명을 붙인 함수명을 가진다.
  • e.stopPropagation(): 이벤트 핸들러가 상위 태그에서 실행되지 않도록 멈춘다.
  • e.preventDefault(): 기존 브라우저 동작을 가진 일부 이벤트가 해당 기본 동작을 실행하지 않도록 방지한다.

이벤트 핸들러 추가

  • 함수를 정의하고 이를 적절한 JSX 태그에 prop 형태로 전달해야 한다.
export default function Button() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}
  1. Button 컴포넌트 내부에 handleClick 함수를 선언한다.
  2. 해담 함수 내부 로직을 구현한다.
  3. <button> JSX에 onClick={handleClick}을 추가한다.

이벤트 핸들러 내에서 Prop 읽기

  • 이벤트 핸들러는 컴포넌트 내부에서 선언되기에 해당 컴포넌트의 prop에 접근할 수 있다.
function AlertButton({ message, children }) {
  return (
    <button onClick={() => alert(message)}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <AlertButton message="Playing!">
        Play Movie
      </AlertButton>
      <AlertButton message="Uploading!">
        Upload Image
      </AlertButton>
    </div>
  );
}

이벤트 핸들러를 Prop으로 전달하기

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

function PlayButton({ movieName }) {
  function handlePlayClick() {
    alert(`Playing ${movieName}!`);
  }

  return (
    <Button onClick={handlePlayClick}>
      Play "{movieName}"
    </Button>
  );
}

function UploadButton() {
  return (
    <Button onClick={() => alert('Uploading!')}>
      Upload Image
    </Button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <PlayButton movieName="Kiki's Delivery Service" />
      <UploadButton />
    </div>
  );
}
  • Toolbar 컴포넌트가 PlayBotton과 UploadButton을 렌더링한다.
    PlayBotton: handlePlayClick을 Button 내 onClick prop으로 전달한다.
    UploadBotton: () => alert('Uploading!')을 Button 내 onClick prop으로 전달한다.
  • Button 컴포넌트는 onClick prop을 받는다.
  • React가 전달받은 함수를 클릭 시점에 호출한다.

이벤트 핸들러 Prop 명명하기

  • on으로 시작하여 대문자 영문으로 이어진다.
function Button({ onSmash, children }) {
  return (
    <button onClick={onSmash}>
      {children}
    </button>
  );
}

export default function App() {
  return (
    <div>
      <Button onSmash={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onSmash={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}

조건부 렌더링

  • if나 조건연산자 같은 자바스크립트 연산자를 사용하여 현재 state를 나타내는 요소를 만들고 React가 UI를 업데이트하여 일치시킨다.

예시) 사용자 로그인 여부에 따라 다음 컴포넌트 중 하나를 표시한다.

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);

요소 변수

  • 컴포넌트의 일부를 조건부로 렌더링하는 데 도움이 되며 나머지 출력은 변경되지 않는다.

로그인/로그아웃 버튼

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

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 isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

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

논리 && 연산자가 있는 인라인 조건

  • 중괄호로 감싸면 JSX에 어떤 표현식이던 넣을 수 있다.
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 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')
);

조건부 연산자를 사용한 인라인 If-Else

  • condition ? true: false

예제 1

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

예제 2

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

리스트

기본 리스트 컴포넌트

  • 보통 리스트를 컴포넌트 안에서 렌더링 한다.
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

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

  • React가 어떤 아이템이 바뀌었는지, 추가되었는지, 삭제되었는지를 인식하는 데 도움을 준다.
  • 요소에 안정적인 ID를 제공하려면 배열 내부 요소에 키를 주어야 한다.
  • 키를 선택하는 가장 좋은 방법은 리스트 아이템의 형제 중 아이템을 고유하게 식별할 수 있는 문자열을 사용하는 것이다. (대부분의 경우 데이터의 ID를 키로 사용)
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);
  • 렌더링된 아이템에서 사용할 안정적인 ID가 없다면, 아이템 인덱스를 키로 넣어 추후에 다시 정렬할 수 있다.
const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);
  • 배열 내에서 사용하는 키는 형제간에 고유해야 한다.
  • 그러나 글로벌로 유니크할 필요는 없으므로 두 다른 배열을 생성할 때 동일한 키를 사용할 수 있어야 한다.
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')
);

키로 컴포넌트 추출

  • 주변 배열의 컨텍스트에서만 의미가 있다.
  • map() 내부의 요소에는 키가 필요하다.
function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}
              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  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>
  );
}

0개의 댓글