어느정도 React문법에 익숙해졌다면 React스타일에 맞추어 효율적인 코드를 작성할 수 있는 방법을 알아보자.
내용은 21 Best Practices for a Clean React Project에 있는 블로그를 번역했고 나름대로 이해한 내용을 추가하였다.
JSX의 축약형을 사용하여 변수를 전달한다. 예를 들어, Navbar 컴포넌트의 타이틀을 표시하는 경우는 다음과 같다.
return (
<Navbar showTitle={true} />
);
return(
<Navbar showTitle />
)
예를 들어 역할에 따라 특정 사용자의 세부 정보를 표시한다고 가정해 보자.
const { role } = user;
if(role === ADMIN) {
return <AdminUser />
}else{
return <NormalUser />
}
const { role } = user;
return role === ADMIN ? <AdminUser /> : <NormalUser />
객체 리터럴은 코드를 읽기 쉽게 만드는 데 도움이 된다. 예를 들어 역할에 따라 세 가지 유형의 사용자를 표시한다고 가정해 보자.
선택 사항이 세 개 이상이므로 위와같이 삼항 연산자를 사용할 수 없을경우 사용할수 있다.
const {role} = user
switch(role){
case ADMIN:
return <AdminUser />
case EMPLOYEE:
return <EmployeeUser />
case USER:
return <NormalUser />
}
const {role} = user
const components = {
ADMIN: AdminUser,
EMPLOYEE: EmployeeUser,
USER: NormalUser
};
const Component = components[role];
return <Componenent />;
div보다 Fragment를 사용한다. 코드를 깨끗하게 유지하고 가상 DOM에 생성되는 노드가 하나 줄어들어 성능에도 도움이 된다.
return (
<div>
<Component1 />
<Component2 />
<Component3 />
</div>
)
return (
<>
<Component1 />
<Component2 />
<Component3 />
</>
)
렌더링 내에서 함수를 정의하지 않는다. 렌더링 내의 로직은 최소한으로 유지한다.
return (
<button onClick={() => dispatch(ACTION_TO_SEND_DATA)}> // NOTICE HERE
This is a bad example
</button>
)
const submitData = () => dispatch(ACTION_TO_SEND_DATA)
return (
<button onClick={submitData}>
This is a good example
</button>
)
React.PureComponent
와 memo
는 불필요한 렌더링을 피할 수 있어 애플리케이션의 성능이 크게 향상된다.
count
는 ChildComponent
과 연관이 없기때문에 자식컴포넌트는 한번만 렌더링하면 되지만 아래코드는 버튼을 클릭할 때마다 렌더링이 실행된다.import React, { useState } from "react";
export const TestMemo = () => {
const [userName, setUserName] = useState("faisal");
const [count, setCount] = useState(0);
const increment = () => setCount((count) => count + 1);
return (
<>
<ChildrenComponent userName={userName} />
<button onClick={increment}> Increment </button>
</>
);
};
const ChildrenComponent =({ userName }) => {
console.log("rendered", userName);
return <div> {userName} </div>;
};
ChildrenComponent
부분을 다음과 같이 수정한다.import React ,{useState} from "react";
const ChildrenComponent = React.memo(({userName}) => {
console.log('rendered')
return <div> {userName}</div>
})
CSS를 정리하는 것은 JavaScript를 정리하는 것보다 훨씬 어렵기 때문에 React애플리케이션을 만들 때는 순수한 JavaScript를 피한다.
// CSS FILE
.body {
height: 10px;
}
//JSX
return <div className='body'>
</div>
const bodyStyle = {
height: "10px"
}
return <div style={bodyStyle}>
</div>
예를 들어 사용자의 세부 정보를 표시해야 한다고 가정해 보자.
return (
<>
<div> {user.name} </div>
<div> {user.age} </div>
<div> {user.profession} </div>
</>
)
const { name, age, profession } = user;
return (
<>
<div> {name} </div>
<div> {age} </div>
<div> {profession} </div>
</>
)
예를 들어 문자열 속성을 자식 컴포넌트에 전달한다고 가정해 봅시다.
return(
<Navbar title={"My Special App"} />
)
return(
<Navbar title="My Special App" />
)
렌더링이나 UI 기능에 도움이 되지 않는 JS 코드는 JSX 밖으로 이동시킨다.
return (
<ul>
{posts.map((post) => (
<li onClick={event => {
console.log(event.target, 'clicked!'); // <- THIS IS BAD
}} key={post.id}>{post.title}
</li>
))}
</ul>
);
const onClickHandler = (event) => {
console.log(event.target, 'clicked!');
}
return (
<ul>
{posts.map((post) => (
<li onClick={onClickHandler} key={post.id}> {post.title} </li>
))}
</ul>
);
큰 문자열을 만들 때는 템플릿 리터럴을 사용한다. 문자열 연결은 피한다.
const userDetails = user.name + "'s profession is" + user.proffession
return (
<div> {userDetails} </div>
)
const userDetails = `${user.name}'s profession is ${user.proffession}`
return (
<div> {userDetails} </div>
)
항상 특정 순서로 지정하면 코드의 가독성이 향상된다.
import React from 'react';
import ErrorImg from '../../assets/images/error.png';
import styled from 'styled-components/native';
import colors from '../../styles/colors';
import { PropTypes } from 'prop-types';
// 빌드인
import React from 'react';
// 외부
import { PropTypes } from 'prop-types';
import styled from 'styled-components/native';
// 내부
import ErrorImg from '../../assets/images/error.png';
import colors from '../../styles/colors';
JavaScript의 기능인 암시적 반환값을 사용한다. 예를 들어 함수가 간단한 계산을 하고 그 결과를 반환한다고 가정해 보자.
const add = (a, b) => {
return a + b;
}
const add = (a, b) => a + b;
컴포넌트에는 Pascal case
를 사용 인스턴스에는 Camel case
를 사용한다.
import reservationCard from './ReservationCard';
const ReservationItem = <ReservationCard />;
import ReservationCard from './ReservationCard';
const reservationItem = <ReservationCard />;
컴포넌트 간 속성의 전달에 DOM 컴포넌트의 속성 이름을 사용하지 않도록 한다.
<MyComponent style="dark" />
<MyComponent className="dark" />
<MyComponent variant="fancy" />
JSX의 속성에는 큰따옴표를 사용하고 그 외의 JS에서는 작은따옴표를 사용한다.
<Foo bar='bar' />
<Foo style={{ left: "20px" }} />
<Foo bar="bar" />
<Foo style={{ left: '20px' }} />
속성 이름에는 항상 Camel case
를 사용하고, 속성 값이 React컴포넌트인 경우는 Pascal case
를 사용합시다.
<Component
UserName="hello"
phone_number={12345678}
/>
<MyComponent
userName="hello"
phoneNumber={12345678}
Component={SomeComponent}
/>
컴포넌트가 여러 줄에 걸쳐 있는 경우는 반드시 괄호로 둘러싸도록 한다.
return <MyComponent variant="long">
<MyChild />
</MyComponent>;
return (
<MyComponent variant="long">
<MyChild />
</MyComponent>
);
컴포넌트에 자식 요소가 없는 경우는 자체 종료 태그를 사용합시다. 가독성이 향상된다.
<SomeComponent variant="stuff"></SomeComponent>
<SomeComponent variant="stuff" />
React의 내부 메소드에서 언더스코어를 사용하지 않는다.
const _onClickHandler = () => {
// do stuff
}
const onClickHandler = () => {
// do stuff
}
<img>
태그에는 반드시 alt 속성을 넣자. 스크린 리더는 이미 img 요소를 이미지로 인식하고 있으므로 alt 속성에 picture나 image와 같은 단어를 사용하지 않아도 된다.
<img src="hello.jpg" />
<img src="hello.jpg" alt="Picture of me rowing a boat" />
alt-bad.jsx
<img src="hello.jpg" alt="Me waving hello" />
절대적인 규칙은 아니지만 되도록 React스타일을 유지함으로써 세련된 코드를 작성할 수 있고 일관된 코드를 작성할 수 있지 않을까 한다.