ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 리액트 입문(2) - 모던 리액트 | 김민준
    Front-end/React.js 2020. 6. 28. 14:04
    반응형

    [출처 : https://react.vlpt.us]

    5. props 를 통해 컴포넌트에게 값 전달하기

    이번에는 컴포넌트의 props 라는 개념에 대해서 알아보겠습니다. props 는 properties 의 줄임말입니다. 우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때, props 를 사용합니다.

    props 의 기본 사용법

    예를 들어서, App 컴포넌트에서 Hello 컴포넌트를 사용 할 때 name 이라는 값을 전달해주고 싶다고 가정해봅시다. 그러면, 이렇게 코드를 작성하면 됩니다.

    App.js :

    import React from 'react';
    import Hello from './Hello';
    
    function App() {
      return (
        <Hello name="React" color="red"/>
      );
    }
    
    export default App;

    이제, Hello 컴포넌트에서 name 값을 사용 하고 싶을 땐 어떻게 하면 되는지 알아볼까요?

    Hello.js :

    import React from 'react';
    
    function Hello(props) {
      return <div style={{ color: props.color }}>안녕하세요 {props.name}</div>
    }
    
    export default Hello;

    컴포넌트에게 전달되는 props 는 파라미터를 통하여 조회 할 수 있습니다. props 는 객체 형태로 전달되며, 만약 name 값을 조회하고 싶다면 props.name 을 조회하면 됩니다.

     

    여러개의 props, 비구조화 할당

    props 내부의 값을 조회 할 때마다 props. 를 입력하고 있는데요, 함수의 파라미터에서 비구조화 할당 (혹은 구조 분해라고도 불립니다) 문법을 사용하면 조금 더 코드를 간결하게 작성 할 수 있습니다.

    Hello.js :

    function Hello({ color, name }) {
      return <div style={{ color }}>안녕하세요 {name}</div>
    }

    defaultProps 로 기본값 설정

    컴포넌트에 props 를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하고 싶다면 컴포넌트에 defaultProps 라는 값을 설정하면 됩니다.

    Hello.js :

    function Hello({ color, name }) {
      ...
    }
    
    Hello.defaultProps = {
      name: '이름없음'
    }

    props.children

    컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회하면 됩니다. 이번에, props.children 을 사용하는 새로운 컴포넌트를 만들어보겠습니다. Wrapper.js 를 src 디렉터리에 만들어보세요.

    /src/Wrapper.js : 

    import React from 'react';
    
    function Wrapper() {
      const style = {border: '2px solid black', padding: '16px',};
      return (
        <div style={style}></div>
      )
    }
    
    export default Wrapper;

    이 컴포넌트를 App 에서 사용해봅시다!

    App.js :

    import Wrapper from './Wrapper';
    
    function App() {
      return (
        <Wrapper>
          <Hello name="react" color="red"/>
          <Hello color="pink"/>
        </Wrapper>
      );
    }

    이렇게 Wrapper 태그 내부에 Hello 컴포넌트 두개를 넣었는데요, 브라우저를 확인하면 다음과 같이 Hello 컴포넌트들은 보여지지 않을 것입니다.

    내부의 내용이 보여지게 하기 위해서는 Wrapper 에서 props.children 을 렌더링해주어야 합니다.

    /src/Wrapper.js :

    function Wrapper() {
      const style = {border: '2px solid black', padding: '16px',};
      return (
        <div style={style}>
          {children}
        </div>
      )
    }

    6. 조건부 렌더링

    조건부 렌더링이란, 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미합니다.

    예를 들어서, App 컴포넌트에서 Hello 컴포넌트를 사용 할 때, isSpecial 이라는 props 를 설정해볼게요.

    App.js :

    function App() {
      return (
        <Wrapper>
          <Hello name="react" color="red" isSpecial={true}/>
          <Hello color="pink" />
        </Wrapper>
      )
    }

    여기서 true 는 자바스크립트 값이기 때문에 중괄호로 감싸주었습니다.

    그리고, Hello 컴포넌트에서는 isSpecial 이 true 이냐 false 이냐에 따라서 컴포넌트의 좌측에 * 표시를 보여줘보겠습니다.

     

    이를 처리하는 가장 기본적인 방법은, 삼항연산자를 사용하는 것 입니다.

    Hello.js : 

    function Hello({ color, name, isSpecial }) {
      return (
        <div style={{ color }}>
          { isSpecial ? <b>*</b> : null }
          안녕하세요 {name}
        </div>
      );
    }

    isSpecial 값이 true 라면 <b>*</b> 를, 그렇지 않다면 null 을 보여주도록 했습니다.

    참고로 JSX 에서 null, false, undefined 를 렌더링하게 된다면 아무것도 나타나지 않게 됩니다. 

     

    보통 삼항연산자를 사용한 조건부 렌더링을 주로 특정 조건에 따라 보여줘야 하는 내용이 다를 때 사용합니다.

    지금은 내용이 달라지는게 아니라, 단순히 특정 조건이 true 이면 보여주고, 그렇지 않다면 숨겨주고 있는데요, 이러한 상황에서는 && 연산자를 사용해서 처리하는 것이 더 간편합니다.

     

    코드를 다음과 같이 수정해보세요.

    Hello.js : 

          ...
          { isSpecial && <b>*</b>}
          ...

    isSpecial && <b>*</b> 의 결과는 isSpecial 이 false 일땐 false 이고, isSpecial이 true 일 땐 <b>*</b> 가 됩니다. 이게 왜 그렇게 되는지 모르겠다면 단축 평가 논리 계산법 을 배워보세요.

     

    props 값 설정을 생략하면 ={true}

    컴포넌트의 props 값을 설정하게 될 때 만약 props 이름만 작성하고 값 설정을 생략한다면, 이를 true 로 설정한 것으로 간주합니다.

    App.js : 

          ...
          <Hello name="react" color="red" isSpecial />
          ...

    이렇게 isSpecial 이름만 넣어주면 isSpecial={true} 와 동일한 의미입니다.


    7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기

    지금까지 우리가 리액트 컴포넌트를 만들 때는, 동적인 부분이 하나도 없었습니다. 값이 바뀌는 일이 없었죠. 이번에는 컴포넌트에서 보여줘야 하는 내용이 사용자 인터랙션에 따라 바뀌어야 할 때 어떻게 구현할 수 있는지에 대하여 알아보겠습니다.

    리액트 16.8 이전 버전에서는 함수형 컴포넌트에서는 상태를 관리할 수 없었는데요, 리액트 16.8 에서 Hooks 라는 기능이 도입되면서 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었습니다. 이번에는 useState 라는 함수를 사용해보게 되는데, 이게 바로 리액트의 Hooks 중 하나입니다.

     

    버튼을 누르면 숫자가 바뀌는 Counter 컴포넌트를 만들어볼게요. src 디렉터리에 Counter.js 를 다음과 같이 작성해보세요.

    /src/Counter.js : 

    import React from 'react';
    
    function Counter() {
      return (
        <div>
          <h1>0</h1>
          <button>+1</button>
          <button>-1</button>
        </div>
      );
    }
    
    export default Counter;
    

    그 다음엔 App 에서 Counter 를 렌더링 해보세요.

    App.js : 

    import React from 'react';
    import Counter from './Counter';
    
    function App() {
      return (
        <Counter />
      );
    }
    
    export default App;

    이벤트 설정

    이제, Counter 에서 버튼이 클릭되는 이벤트가 발생 했을 때, 특정 함수가 호출되도록 설정을 해보겠습니다.

    Counter 컴포넌트를 다음과 같이 수정해보세요.

    /src/Counter.js : 

    function Counter() {
      const onIncrease = () => {
        console.log('+1')
      }
      const onDecrease = () => {
        console.log('-1');
      }
      return (
        <div>
          <h1>0</h1>
          <button onClick={onIncrease}>+1</button>
          <button onClick={onDecrease}>-1</button>
        </div>
      );
    }

    여기서 onIncrease 와 onDecrease 는 화살표 함수를 사용하여 구현을 해주었는데요, 화살표 함수에 대해서 잘 모르신다면 이 링크 를 참고하세요. 함수를 만들고, button 의 onClick 으로 각 함수를 연결해주었습니다. 리액트에서 엘리먼트에 이벤트를 설정해줄때에는 on이벤트이름={실행하고싶은함수} 형태로 설정해주어야 합니다.

     

    여기서 주의하셔야 하는 점은, 함수형태를 넣어주어야 하지, 함수를 다음과 같이 실행하시면 안됩니다.

    onClick={onIncrease()}

    이렇게 하면 렌더링되는 시점에서 함수가 호출되버리기 때문입니다. 이벤트를 설정할때에는 함수타입의 값을 넣어주어야 한다는 것, 주의해주세요.

     

    동적인 값 끼얹기, useState

    컴포넌트에서 동적인 값을 상태(state)라고 부릅니다. 리액트에 useState 라는 함수가 있는데요, 이것을 사용하면 컴포넌트에서 상태를 관리 할 수 있습니다.

    Counter 컴포넌트를 다음과 같이 수정해보세요.

    /src/Counter.js :

    // 아래 코드는 리액트 패키지에서 useState 라는 함수를 불러와줍니다.
    import React, { useState } from 'react';
    
    function Counter() {
      const [number, setNumber] = useState(0);
      const onIncrease = () => {
        // Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정해줍니다.
        setNumber(number + 1); 
      }
      const onDecrease = () => {
        setNumber(number - 1);
      }
    
      return (
        <div>
          // h1 태그에서는 이제 0 이 아닌 {number} 값을 보여주어야 합니다. 
          <h1>{number}</h1>
          ...
      );
    }
    const [number, setNumber] = useState(0);

    useState 를 사용 할 때에는 상태의 기본값을 파라미터로 넣어서 호출해줍니다. 이 함수를 호출해주면 배열이 반환되는데요, 여기서 첫번째 원소는 현재 상태, 두번째 원소는 Setter 함수입니다.

     

    원래는 다음과 같이 해야하지만,

    const numberState = useState(0);
    const number = numberState[0];
    const setNumber = numberState[1];

    배열 비구조화 할당을 통하여 각 원소를 추출해준것입니다.

     

    함수형 업데이트

    지금은 Setter 함수를 사용 할 때, 업데이트 하고 싶은 새로운 값을 파라미터로 넣어주고 있는데요, 그 대신에 기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하는 방식으로도 값을 업데이트 할 수 있습니다.

    Counter 컴포넌트를 다음과 같이 수정해보세요.

    /src/Counter.js :

    function Counter() {
      const [number, setNumber] = useState(0);
      const onIncrease = () => {
        setNumber(prevNumber => prevNumber + 1);
      }
      const onDecrease = () => {
        setNumber(prevNumber => prevNumber - 1);
      }
    
      return (
        ...
      );
    }

    onIncrease 와 onDecrease 에서 setNumber 를 사용 할 때 그 다음 상태를 파라미터로 넣어준것이 아니라, 값을 업데이트 하는 함수를 파라미터로 넣어주었습니다.

    함수형 업데이트는 주로 나중에 컴포넌트를 최적화를 하게 될 때 사용하게 됩니다. 지금 당장은 함수형 업데이트란게 있는 것 정도만 이해해두시면 충분합니다. 이게 왜 최적화랑 관련이 되어있는지는 나중에 알아보도록 할게요.

    반응형

    댓글

Luster Sun