리액트 초보자를 위한 7가지 팁 정리
1. 컴포넌트 name 설정
버그가 있는 컴포넌트를 파악하려면 항상 컴포넌트에 이름을 지정하는 것이 중요하다. React Router 또는 외부 라이브러리를 사용하기 시작하면 더욱 그렇다.
// Avoid thoses notations
export default () => {};
export default class extends React.Component {};
default본 export를 사용할지 named export를 사용할지에 대한 논쟁이 있다. default export는 컴포넌트명이 프로젝트에서 일관되도록 보장하지 않는다. 게다가 트리 쉐이킹에 덜 효과적이다.
2. 컴포넌트를 expose하는 방법에 관계없이 이름 설정
컴포넌트를 호스팅 하는 클래스 이름 또는 변수명을 정의해야 한다. 리액트는 실제로 오류 메시지에서 컴포넌트명을 유추한다.
export const Component = () => <h1>I'm a component</h1>;
export default Component;
// Define user custom component name
Component.displayName = 'My Component';
그리고 ESLint를 사용하는 경우 다음 두 가지 규칙을 설정하는 것을 고려해야 한다.
"rules": {
// Check named import exists
"import/named": 2,
// Set to "on" in airbnb preset
"import/prefer-default-export": "off"
}
3. Functional 컴포넌트 사용
데이터 표시만을 목적으로 하는 컴포넌트가 많은 경우 React 컴포넌트를 정의하는 다양한 방법을 활용한다.
class Watch extends React.Component {
render () {
return <div>{this.props.hours}:{this.props.minutes}</div>
}
}
// Equivalent functional component
const Watch = (props) =>
<div>{props.hours}:{props.minutes}</div>;
방법 모두 동일한 Watch 컴포넌트를 정의한다. 그러나 두 번째는 JSX 템플릿의 props에 접근하기 더 짧고 this가 필요 없다.
4. div를 프래그먼트(Fragments)로 바꾸기
모든 컴포넌트는 고유한 루트 요소를 템플릿으로 노출해야 한다. 이 규칙을 준수하기 위한 일반적인 수정은 템플릿을 div로 감싸는 것이었다. 하지만 리액트 16부터 Fragments라는 새로운 기능을 제공한다. 쓸모없는 divs를 React.Fragments로 바꿀 수 있다. 출력 템플릿은 래퍼가 없는 Fragment 콘텐츠다.
const Login = () =>
<div><input name="login"/><input name="password"/></div>;
const Login = () =>
<React.Fragment><input name="login"/><input name="password"/></React.Fragment>;
const Login = () => // Short-hand syntax
<><input name="login"/><input name="password"/></>;
5. 상태를 설정할 때 주의하기
리액트 앱이 동적이 되는 즉시 컴포넌트의 상태를 처리해야 한다. constructor에서 상태를 초기화한 다음 setState로 상태를 설정한다. 어떤 이유로 상태의 값을 설정하기 위해 setState를 호출할 때 현재 상태 또는 소품 값을 사용해야 할 수도 있다.
// Very bad pratice: do not use this.state and this.props in setState !
this.setState({ answered: !this.state.answered, answer });
// With quite big states: the tempatation becomes bigger
// Here keep the current state and add answer property
this.setState({ ...this.state, answer });
문제는 리액트가 this.state와 this.props의 값을 보장하지 않고 가지고 있다는 것이다. 상태 업데이트가 DOM 조작을 최적화하기 위한 일괄 처리이기 때문에 this.state는 비동기로 동작한다.
// Note the () notation around the object which makes the JS engine
// evaluate as an expression and not as the arrow function block
this.setState((prevState, props) => ({ ...prevState, answer}));
setState를 사용할 때 상태 손상을 예방하려면 매개변수와 함께 사용해야 한다.
6. Binding 컴포넌트 functions
element의 이벤트를 컴포넌트에 바인딩하는 방법에는 여러 가지가 있지만 일부는 권장되지 않는다. 첫 번째 방법은 리액트 문서에 나와있다.
class DatePicker extends React.Component {
handleDateSelected({target}){
// Do stuff
}
render() {
return <input type="date" onChange={this.handleDateSelected}/>
}
}
위 코드는 작동하지 않는다. 그 이유는 JSX를 사용할 때 this 값이 컴포넌트 인스턴스에 바인딩되지 않기 때문이다. 작동하도록 하는 방법은 다음과 같다.
// #1: use an arrow function
<input type="date" onChange={(event) => this.handleDateSelected(event)}/>
// OR #2: bind this to the function in component constructor
constructor () {
this.handleDateSelected = this.handleDateSelected.bind(this);
}
// OR #3: declare the function as a class field (arrow function syntax)
handleDateSelected = ({target}) => {
// Do stuff
}
첫 번째 예에서와 같이 JSX에서 화살표 함수를 사용하는 것이 처음에는 매력적으로 보인다. 하지만 이렇게 하면 안 된다. 실제로 각 컴포넌트 렌더링 시 화살표 기능이 다시 생성되어 성능이 저하된다.
7. 컨테이너 패턴 사용 (Redux 포함)
마지막으로 컨테이너 디자인 패턴이다. 이를 통해 리액트 컴포넌트의 관심사 분리 원칙을 따를 수 있다.
export class DatePicker extends React.Component {
state = { currentDate: null };
handleDateSelected = ({target}) =>
this.setState({ currentDate: target.value });
render = () =>
<input type="date" onChange={this.handleDateSelected}/>
}
단일 컴포넌트가 동일한 위치에서 템플릿 렌더링 및 사용자 작업을 처리한다. 대신 두 가지 컴포넌트를 사용하자.
const DatePicker = (props) =>
<input type="date" onChange={props.handleDateSelected}/>
export class DatePickerController extends React.Component {
// ... No changes except render function ...
render = () =>
<DatePicker handleDateSelected={this.handleDateSelected}/>;
}
여기에 트릭이 있다. DatePickerContainer가 필요한 경우 사용자 상호 작용 및 API 호출을 처리한다. 그런 다음 DatePicker를 렌더링하고 supplies props를 전달한다. 이 패턴 덕분에 컨테이너 컴포넌트가 프레젠테이션 컴포넌트를 대체할 수 있다. 이 functional component는 props가 없으면 쓸모가 없다.
export const DatePickerContainer =
connect(mapStateToProps, mapDispatchToProps)(DatePickerController);
또한 Redux를 앱의 상태 관리자로 사용하는 경우에도 이 패턴과 잘 연결된다. 이 connect함수는 컴포넌트에 props를 주입한다. 우리의 경우 해당 props를 컴포넌트로 전달할 컨트롤러를 공급합니다. 따라서 두 컴포넌트 모두 Redux 데이터에 접근 할 수 있다.
참고
'development' 카테고리의 다른 글
타입스크립트 인터페이스 선언 머지 (Interface Declaration Merging) (0) | 2022.12.01 |
---|---|
AWS 이미지를 업로드하는 4가지 방법 (0) | 2022.11.30 |
Gatsby 사이트에 애드센스(AdSense) 적용하기 (0) | 2022.11.29 |
Phaser 개발환경 세팅 (0) | 2022.10.04 |
크롬 캐시 끄기(비활성화) (0) | 2022.10.03 |