알고 있지만 자주 하는 실수들을 방지하기 위해서 사용 중인 ESLint 룰 몇 가지를 소개합니다.
이번에도 누군가에게는 도움이 되길 바랍니다.
아래에서 수정이나 개선이 필요한 곳들을 찾아보세요.
// Example A
function ExampleComponent() {
const message = 'I like RN~';
return (
<View style={[styles.container]}>
<View style={{
flex: 1,
}} />
<TouchableOpacity onPress={() => console.log('Hello!')}>
<Text style={styles.text}>Hi~ RN!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
...
},
text: {
...
},
message: {
...
},
});
// Example B
class MyComponent extends React.Component {
render() {
...
}
}
몇 개나 찾으셨나요? 다 찾지 못했어도 괜찮아요. 이제부터 알면 되니까요.
불필요한 스타일 정의
디자인이 자주 변경되다 보면 더는 필요 없어진 스타일의 정의를 삭제하는 걸 잊어먹기 쉽습니다. 위 코드에서 message는 더 이상 사용되는 곳이 없으니 삭제해야 합니다. 이런 것들이 수백 개의 컴포넌트에 남아있다고 생각해보세요. @_@
const styles = StyleSheet.create({
container: {
...
},
text: {
...
},
**message: { // 삭제!
...
},**
});
불필요한 변수
RN의 기본 ESLint 설정에서는 경고로 처리되는데 에러로 변경해서 보이는 즉시 정리해주는 게 좋아요. 경고도 계속 보다 보면 눈에 익숙해져서 자동 필터링이 되더라고요.
export function ExampleComponent() {
**const message = 'I like RN~'; // 삭제!**
인라인 스타일/함수 사용
컴포넌트의 속성에 인라인으로 객체나 함수를 전달하면 안 됩니다. 컴포넌트가 렌더링 될 때 속성에 같은 역할을 하는 값을 전달해도 새로운 값으로 인식되기 때문에 불필요한 리렌더링이 발생하니까요. 가장 많은 분들이 하는 실수이자 잘못된 습관입니다. 성능을 떠나서도 인라인이 잔뜩 들어간 뷰(레이아웃) 정의는 가독성이 너무 떨어지기 때문에 오늘부터라도 인라인을 사용하지 않는 습관을 가져보세요.
<View style={**{
...
}**} />
<TouchableOpacity onPress={**() => console.log('Hello!')**}>
// 아래처럼 사용해야겠죠!
<View style={styles.message} />
<TouchableOpacity onPress={this.onPress}>
함수를 전달할 때 클래스 컴포넌트라면 Arrow Function을 사용하면 되고
class ExampleComponet extends PureComponent {
onPress = () => {};
render() {
return (<TouchableOpacity onPress={this.onPress}> ... );
}
}
함수 컴포넌트라면 useCallback 훅을 사용해서 캐시 된(memoized) 함수를 전달해 주시면 됩니다. 간혹 아래와 같이 함수를 인라인으로 생성해서 전달하는 경우가 있는데요. 자바스크립트 엔진에서 매번 생성되지 않도록 최적화가 되더라도 onPress는 매번 다른 객체가 됩니다. 같은 이유로 내부에서 사용되는 객체라면 useMemo 훅으로 캐시 하면 좋아요. (리렌더링이 발생하지 않는다면 쓰지 않는 것이 더 효율적입니다.)
// 비효율적인 사용
function ExampleComponent() {
const onPress = () => {
...
}
const containerStyle = [..., ..., ...];
return (<TouchableOpacity style={containerStyle} onPress={onPress}> ... );
}
// 효율적인 사용
function ExampleComponent() {
const onPress = useCallback(() => {
...
}, []);
const {
containerStyle,
textStyle,
} = useMemo(() => ({
containerStyle: [..., ..., ...],
textStyle: [..., ..., ...],
}, []);
return (<TouchableOpacity style={containerStyle} onPress={onPress}> ... );
}
불필요한 배열 사용
조건들이 있어서 배열 방식의 스타일 정의를 사용했다가 스펙이 변경되면서 아래처럼 불필요한 배열만 덩그러니 남는 경우가 흔하지는 않지만 아주 가끔씩 발생합니다. 인라인 스타일과 같은 이유로 속성에 배열을 전달하면 효율적으로 렌더링 되지 않기 때문에 불필요한 배열은 제거하셔야 해요.
<View style={**[styles.container]**}>
비효율적인 Component 사용
클래스 컴포넌트를 사용한다면 특별한 이유가 있는 게 아니라면 일반적으로 PureComponent
를 사용하는 것이 좋습니다. Component
를 사용한다면 shouldComponentUpdate
함수를 잘 정의해서 불필요한 렌더링을 방지해줘야 하고요. 함수 컴포넌트를 사용한다면 React.memo
를 적절하게 사용해주시고요.
**class TestComponent extends React.Component {**
모든 걸 다 신경 쓰면서 실수 없이 코드를 작성하는 건 쉬운 일이 아닌데요. 걱정 마세요. ESLint가 있으니 어렵지 않아요! 설마 아직까지 ESLint를 사용하지 않고 계시진 않겠죠? 😅
RN 프로젝트를 생성하면 기본 생성되는 .eslintrc.js
파일을 열어보시면 @react-native-community/eslint-config
패키지를 사용하도록 설정되어 있어요. 여기에 해당 프로젝트에서 사용할 룰을 추가 및 재정의 해주시면 됩니다.
module.exports = {
root: true,
extends: '@react-native-community',
rules: {
// 불필요한 스타일
'react-native/no-unused-styles': 2,
// 불필요한 변수
'no-unused-vars': [
2,
{vars: 'all', args: 'after-used', ignoreRestSiblings: true},
],
// 불필요한 배열
'react-native/no-single-element-style-arrays': 2,
// 인라인 스타일
'react-native/no-inline-styles': 2,
// 인라인 함수
'react/jsx-no-bind': 2,
// 비효율적인 Component
'react/require-optimization': 2,
},
};