확장성을 고려한 React 컴포넌트

defaultProps, propTypes

Button.defaultProps = { buttonLabel: "Submit" };

Button.propTypes = {
  handler: PropTypes.func.isRequired,
  title: PropTypes.string,
  email(props, propName, componentName) {
    let emailRegularExpression = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
    if (!emailRegularExpression.test(props[propName])) {
      return new Error("Email validation failed!");
    }
  }
};

예제 코드
typechecking-with-proptypes

커링

  • 커링은 1967년 Christopher Strachey 가 Haskell Brooks Curry의 이름에서 사용 됨.
  • 커링이란 다중인자를 받는 함수를 단일 인자 함수열로 만드는 것을 말함.
/* Function expression */
function calc(f) {
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

/* Arrow function expression */
const calc = f => a => b => f(a, b);

const sum = calc((a, b) => a + b);
console.log(sum(10)(5)); // 15

const sub = calc((a, b) => a > b ? a - b : b - a);
console.log(sub(15)(5)); // 10

const sum10 = sum(10); // (10, b) => b + 10
const sub15 = sub(15); // (a, 5) => 5 - a
console.log(sum10(sub15(10))); // 15

커링을 이용한 HOF 만들기

function noisy(f) {
  return (...args) => {
    console.log("calling with", args);
    let result = f(...args);
    console.log("called with", args, ", returned", result);
    return result;
  };
}

noisy(Math.min)(3, 2, 1);

커링으로 동작 추상화

const map = transform => array => {
  let mapped = [];
  for (let element of array) {
    mapped.push(transform(element));
  }
  return mapped;
};

const filter = test => array => {
  let passed = [];
  for (let element of array) {
    if (test(element)) {
      passed.push(element);
    }
  }
  return passed;
};

console.log(_map(n => n * n)([1, 2, 3]));
console.log(filter(n => n % 2)([1, 2, 3, 4, 5]));
console.log(map(n => n * n)(filter(n => n % 2)([1, 2, 3, 4, 5])));

예제 코드
Higher-Order Functions
커링

HOC(High-Order Component)

Higher Order Components는 무엇일까?

  • Higher Order Component는 다른 컴포넌트를 감싸는 리액트 컴포넌트

HOC로 무엇을 할 수 있을까?

높은 수준의 HOC를 사용하면 다음과 같은 것을 할 수 있다.

  • 코드 재사용, 로직 및 부트스트랩 추상화
  • Render Highjacking (HOC는 래핑 된 요소의 모든 작업을 조작 가능하므로 하이재킹(강탈, 납치)라는 단어를 사용하는듯)
  • 상태 추상화 및 조작(manipulation)
  • props 조작(manipulation)

기본 HOC의 구조

function withSubscription(WrappedComponent) {
  /* 새로운 Component 구현 */
  class WithSubscription extends React.Component { ... }

  /* Component 이름 정의*/
  WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`; 

  /* Component 반환 */
  return WithSubscription;
}

Logger과 Color를 입히는 간단한 HOC 만들기

const withLogger = WrappedComponent => {
  class WithLogger extends React.Component {
    componentDidUpdate() {
      console.log('componentDidUpdate');
    }
    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  WithLogger.displayName = `WithLogger(${WrappedComponent.displayName})`;
  return WithLogger;
};

const withColor = color => WrappedComponent => {
  class WithColor extends React.Component {
    render() {
      return <div style={{color: color}}><WrappedComponent {...this.props} /></div>;
    }
  }

  WithColor.displayName = `WithColor(${WrappedComponent.displayName})`;
  return WithColor;
}

const Title = ({ text }, props, actions) => {
  return (
    <div>
      <h1>{text}</h1>
    </div>
  );
};

const NewTitle = withLogger(withColor('blue')(Title));

예제 코드

비동기 API를 사용하는 HOC 만들기

const API = "https://hn.algolia.com/api/v1/search?query=";
const DEFAULT_QUERY = "redux";

const withFetching = url => Component =>
  class WithFetching extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        data: null,
        isLoading: false,
        error: null
      };
    }

    componentDidMount() {
      this.setState({ isLoading: true });

      axios
        .get(url)
        .then(result =>
          this.setState({
            data: result.data,
            isLoading: false
          })
        )
        .catch(error =>
          this.setState({
            error,
            isLoading: false
          })
        );
    }

    render() {
      return <Component {...this.props} {...this.state} />;
    }
  };

예제 코드