프로젝트가 끝난 후, 코드는 남지만 코드를 생각해내기까지의 고민과 과정은 쉽게 휘발된다. 이를 붙잡기위해 적어보는 기억에 남는 코드록
기본적으로 사용되는 fetch 함수 형태는 아래와 같다.
하지만 위의 fetch함수가 여러 번 반복되어 사용된다면 가독성이 현저히 떨어진다.
리팩토링의 중요한 원칙 중 하나 = 반복되는 요소를 축약시키자
위 함수에서 각각의 색으로 테두리친 fetch함수, 두 번의 then함수와 setState부분을 아래와 같이 변수화해서 가독성은 챙기고, 코드의 길이는 줄일 수 있다.
const updateProducts = data => this.setState({ products: data.Result });
const updateMain = data => this.setState({ main: data.Result });
setState 부분을 살펴보니 state 중 products
혹은 main
을 변경하는 것으로 나뉘었다. 이 부분을 각각 변수 한 단어로 설정해 축약했다.
반복되는 함수가 있다 => 함수의 틀을 만들고, 바꾸어서 재사용하자.
fetch함수 및 두 번의 then 함수
를 하나의 함수로 만들었다.
여기서 변경되는 부분은 API와 setState 부분이니 각각 (setState부분은 callback함수로) 인자로 설정했다.
handleFetch = (API, callback) => {
fetch(API)
.then(res => res.json())
.then(data => {
callback(data);
});
};
위 함수에서의 callback(data)
는 변수화해두었던 setState인 updateProducts
, updateMain
으로 대체할 수 있다.
그럼 아래 처럼 정-말 많이 축약된 코드로 같은 기능을 구현할 수 있다!
//state의 products update
handleFetch(API, updateProducts);
//state의 main update
handleFetch(API, updateMain);
실제로 카테고리 상품 리스트 페이지 내에서 총 3번의 fetch가 이루어져야 했는데, 변수화를 통해 가독성을 높힐 수 있었다. fetch함수는 앞으로 질리도록 쓰게 될테니 잘 기억해두고 두고두고 써먹어야지
const FILTER_BTN_DATA = [
{
id: 1,
filter: 'name',
text: '이름순',
},
{
id: 2,
filter: 'updated_at',
text: '최신순',
},
{
id: 3,
filter: '-grade',
text: '인기순',
},
{
id: 4,
filter: 'price',
text: '낮은 가격순',
},
{
id: 5,
filter: '-price',
text: '높은 가격순',
},
{
id: 6,
filter: 'dgree',
text: '낮은 도수순',
},
{
id: 7,
filter: '-dgree',
text: '높은 도수순',
},
];
위와 같이 상수 데이터에 map함수를 돌려 버튼 컴포넌트를 나타냈는데, 그 중 filter
속성에 쿼리스트링으로 보낼 값들을 적어주었다. (이 때 백엔드 측과 협의 필수)
// 최상위 컴포넌트
// state 중 filter항목을 update하는 handleFilter 함수 구현
handleFilter = e => {
this.setState({
filter: e,
});
};
// 버튼 컴포넌트
// onClick이벤트로 handleFilter 함수 호출.
// 이 때 인자는 이벤트 타겟의 id(=상수데이터에서 받아온 각각의 filter값)이다.
// 따라서 버튼 클릭시 해당 버튼의 filter 값으로 최상위 컴포넌트 state의 filter 값이 바뀌는 셈
const { currentFilter, filter, handleFilter, text } = this.props;
return (
<button
className={`filter-btn ${
currentFilter === filter ? 'yellow-btn' : 'gray-btn'
}`}
onClick={e => {
handleFilter(e.currentTarget.id);
}}
id={filter}
>
{text}
</button>
)
state가 변경되니 componentDidUpdate를 통해 fetch를 해주어야 한다.
이전 filter와 현재 filter가 변경되었을 때를 비교하고,
값이 서로 다를 경우 앞서 축약해주었던 형태로 fetch를 다시 해준다.
componentDidUpdate(prevProps, prevState) {
const updateProducts = data => this.setState({ products: data.Result });
if (this.state.filter !== prevState.filter) {
this.handleFetch(
`${API}/products/list?limit=20&order-by=${this.state.filter}&category=${this.props.match.params.id}`,
updateProducts
);
}
}
실제 사이트엔 없는 기능이지만, 팀원들과 상의한 후 새롭게 추가한 기능인 안주 검색 기능
프론트엔드 단에서 구현을 해야할지, 글씨를 입력할 때마다 바로바로 검색되게 해야할지.. 팀원들과 많은 고민을 한 끝에 가장 안정적으로 결과물이 나타난다고 생각되는 쿼리스트링을 통한 구현을 선택했다.
state update 함수 만들기
handleSideDishInput = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
위와 같이 이벤트 타겟의 name : value 형태로 state를 update하는 함수를 만들고
state update 함수를 input에 넘겨주기
<input
className="filter-input"
placeholder="어떤 안주와 즐기고 싶으세요?"
name="sideDish"
onChange={this.props.handleSideDishInput}
/>
이 함수를 input에 onChange 이벤트로 걸어준다.
input의 name은 sideDish로 입력해두었다. 결과적으로 input에 입력하는 값은 {sideDish(input의 name):input의 입력값}
형태로 state에 저장된다.
이제 input의 입력값을 쿼리스트링 안에 넣어 서버로 보내주자!
쿼리스트링으로 검색값을 넘겨주는 함수 만들기
handleSideDish = () => {
this.handleFetch(
`${API}/products/list?order-by=${this.state.filter}&category=${this.props.match.params.id}&side-dish=${this.state.sideDish}`,
data =>
this.setState({
products: data.Result,
})
);
};
위 코드에서 우리가 주목해야 할 부분은 side-dish=${this.state.sideDish}
handleSideDish 함수를 통해 우리는 fetch를 할 건데, 이 때 URL의 쿼리스트링에 state의 값을 넘겨준다.
검색값을 넘겨주는 함수를 버튼에 넘겨주기
검색 기능을 실행시킬 버튼을 클릭할 때마다 해당 함수가 호출되도록 onClick이벤트를 걸어주면 끝!
<button
className="filter-side-dish-btn"
onClick={this.props.handleSideDish}
>
안주로 검색하기
</button>
와 동희님 너무 좋은 기획인거같아요!🙌🙌 저도 나중에..기억이 더 증발되기 전에 기록을 남기는 습관을 들여야겠습니다!