React 기반 Refactoring 도전기

미키오·2022년 12월 4일
0
post-thumbnail

HTML, CSS, JS 기반 refactoring 에 대해 다룬 지난 글에 이어서 이번에는 React로 만든 코드의 refactoring 가이드라인을 해보았다. 백번 강조해도 부족하지 않을 가독성 향상과 유지보수의 용이성을 위해.. 오늘도 리팩토링을 해보자.

점점 벨로그 글 쓰는 시간보다 짤 찾는 시간이 더 길어지는 기분이다

1. import 순서

제일 첫번째로 React 문서의 최상단에 정리되지 않은 import부터 정리해주자.

// 정리 전
import React, { useEffect, useState } from 'react';
import './Main.scss';
import logo from"./assets/logo.png";
import {useNavigate} from 'react-router-dom;
import Comment from './Comment';
import WestaAside from './WestaAside';
import Feed from './Feed';

권장 import 순서:

  1. 라이브러리
    • React 관련 패키지
    • 외부 라이브러리
  2. 컴포넌트
    • 공통 컴포넌트
    • 현재 컴포넌트 기준 상대적으로 먼 컴포넌트
    • 현재 컴포넌트 기준 상대적으로 가까운 컴포넌트
  3. 함수, 변수 및 설정 파일
  4. 사진 등 미디어 파일
  5. CSS 파일
// 정리 후
import React, { useEffect, useState } from 'react';
import {useNavigate} from 'react-router-dom;
import Feed from './Feed';
import Comment from './Comment';
import WestaAside from './WestaAside';
import logo from"./assets/logo.png";
import './Main.scss';

각 기능별로 순서별로 정리하니 가독성이 올라갔다 :)

2. 함수 영역

1) 함수는 한 가지 기능만 사용

한 가지 함수에 많은 기능이 함유되어 있다면 원하는 일부분의 기능만 사용하기가 쉽지 않다. 리액트의 최고 장점인 재사용성을 극대화하려면 함수는 한 가지 기능만 수행하도록 최대한 작게 쪼개야 한다.

// 분리 전
const handleSignupAndLogin = () => {...};
// 분리 후
const handleSignup = () => {...};
const handleLogin = () => {...};

2) 함수 매개변수에서 바로 비구조화 할당

ES6의 문법 중 하나로 비구조화 할당을 통해 배열이나 객체의 속성을 해체하여 변수에 담을 수 있다. 비구조화 할당의 특징으로는 코드의 직관성과 간결성을 높일 수 있고 두번 이상 객체의 이름을 넣는 경우에 사용하는 것을 권장한다.

// 일반 함수
const student = {
	name : "mikio",
    className : "Algorithm",
    result: "A"
    };
    
    const getStudentInfo = ({name, className, result}) => {
    	return '학생의 이름은 ${name}이고 수강한 강의명은 ${className}이며 성적은 ${result}입니다..';
        
 getStudentInfo(student);
    
// 컴포넌트 함수

// StudentList.js
const StudentList = () => {
	return (
    	<ul>
        	{STUDENT_LIST.map(student => (
            	<li key = {student.id}>
                	<StudentResult student = {student} />
                </li>
            ))}
        </ul>
    );
};

// StudentResult.js
const StudentResult = ({student: { name, grade, result }}) => {
	return (
    	<>
        	<span>{name}</span>
            <span>{grade}</span>
            <span>{result}</span>
        </>
    );
};

3) 계산된 속성명을 이용한 input Handler 함수 합치기

이 역시 ES6부터 지원되는 기능으로 계산된 속성명이란 객체의 속성명이 동적으로 결정되는 것을 의미한다.
input 태그의 name이라는 속성과 계산된 속성명을 함께 이용하면 여러 개의 input handler를 합칠 수 있다. (name 속성은 오직 input 태그에서만 사용할 수 있다.)

수정 전)

수정 후)

4) Boolean 데이터 타입 활용

if 조건문으로 작성한 코드를 Boolean 데이터 타입 특성인 삼항 연산자나 논리연산자를 활용하면 더 직관적이고 간결한 코드작성이 가능해진다.

// Before

const ChangeBtn = () => {
	if (input.id.includes('@') && input.pw.length >= 5) {
    	setIsValid(true);
    } else {
   		setIsValid(false);
    }
};
// After1 : 삼항 연산자 활용

const ChangeBtn = () => {
	input.id.includes('@') && input.pw.length >= 5
    	? setIsValid(true)
        : setIsValid(false);
    };
// After2 : 논리 연산자 활용

const ChangeBtn = () => {
  const isValid = input.id.includes('@') && input.pw.length >= 5;
  setIsValid(isValid);
};

3. JSX 영역

1) 인라인 사용 지양 및 CSS 클래스 지향

인라인 스타일은 가장 높은 우선 순위를 가지기 때문에 CSS에서 지정한 스타일이 적용되지 않을수도 있으며 유지 보수가 어렵고 재사용성에 좋지 않다. 또한 CSS 클래스가 인라인 스타일보다 더 나은 성능을 보이므로 CSS 클래스 사용을 권장한다.

// Bad
<button style = {{color : isValid ? 'blue' : 'white'}}>
로그인
</button>
import 'style.css';

<button className ={isValid ? 'activated' : 'deactivated'}>
로그인
</button>

<Link>는 브라우저의 주소만 바꿀 뿐 페이지를 새로 불러오지 않아서 렌더링 최적화를 위해서는 꼭 사용하는 것이 좋다. 반면에 html의 <a>태그를 사용하면 페이지 자체를 새롭게 불러오게 되면서 앱의 상태가 초기화되고 렌더링 되니 컴포넌트도 모두 사라지고 새로 렌더링을 해야 한다. 따라서 React를 사용한 개발 과정에서는 <Link> 를 사용하는 것을 권장한다.

3) Array.map() 활용을 통한 불필요한 반복성 줄이기

map 함수를 사용하면 불필요한 하드코딩 과정을 줄일 수 있다. 또한 데이터가 새로 추가되는 과정에서 유지보수하기 더욱 용이해진다.

//Bad

const Footer = () => {
  return (
    <div>
      <li>
        <Link to="/help">도움말</Link>
      </li>
      <li>
        <Link to="/promotion">홍보 센터</Link>
      </li>
      <li>
        <Link to="/api">API</Link>
      </li>
      <li>
        <Link to="/recruitment">채용정보</Link>
      </li>
      <li>
        <Link to="/privacy">개인정보처리방침</Link>
      </li>
    </div>
  );
};
// Good

// footerData.js

export const INFO_LIST = [
  { id: 1, content: '도움말', url: '/help' },
  { id: 2, content: '홍보 센터', url: '/promotion' },
  { id: 3, content: 'API', url: '/api' },
  { id: 4, content: '채용정보', url: '/recruitment' },
  { id: 5, content: '개인정보처리방침', url: '/privacy' },
];


// Footer.js

import React from 'react';
import { Link } from 'react-router-dom';
import { INFO_LIST } from './footerData';

const Footer = () => {
  return (
    <div>
      {INFO_LIST.map(info => {
        return (
          <li key={info.id}>
            <Link to={info.url}>{info.content}</Link>
          </li>
        );
      })}
    </div>
  );
};

INFO_LIST 같이 값이 변하지 않는 변수(상수)를 컴포넌트의 바디 안에서 선언할 경우 컴포넌트가 리렌더링 될 때마다 새로운 변수로 계속 선언된다.. 그러므로 컴포넌트 바디 밖에서 선언하거나 따로 파일을 생성하여 분류하는 것이 좋다.

profile
교육 전공 개발자 💻

0개의 댓글