본문 바로가기

2주차

동적 필터링 구현

안녕하세요 웹 OB 이예림입니다..! 

 

과제를 구현하던 중, 아래와 같이 각각의 함수로 필터링하는 방식이 매우 비효율적으로 느껴졌는데요,

🤔 필터링을 재사용한 것처럼, 동적으로 접근하는 방식이 있지 않을까? 라는 의문으로 해당 주제를 접하게 되었습니다.

 

  const selectedGender = getSelectValue("sel_gender");
  const selectedRole = getSelectValue("sel_role");
  const inputName = getInputName();
  const inputEnName = getInputValue("enNameInput");
  const inputGithub = getInputValue("githubInput");
  const inputWeek1 = getInputNumber("week1Input");
  const inputWeek2 = getInputNumber("week2Input");

  // 필터링
  const filteredGender = filterGenderOrRole(
    memberList,
    "gender",
    selectedGender
  );
  const filteredRole = filterGenderOrRole(filteredGender, "role", selectedRole);
  const filteredName = filterName(filteredRole, inputName);
  const filteredEnName = filterEnNameOrGit(filteredName, "enName", inputEnName);
  const filteredGithub = filterEnNameOrGit(
    filteredEnName,
    "github",
    inputGithub
  );
  const filteredWeek1 = filterWeek(filteredGithub, "week1", inputWeek1);
  const filteredMembers = filterWeek(filteredWeek1, "week2", inputWeek2);

  renderMemberList(filteredMembers); // 필터링된 리스트 렌더링
});

 

1. 객체로 필터 조건을 관리

: 이전 코드의 경우,

filterGenderOrRole(filteredGender, "role", selectedRole);

개별 필터 함수에 순서대로 (멤버리스트, 키값, 필터 값)을 전달했는데요, 이를 개별 함수로 처리하지 않고 filters 객체를 활용하여 필터 값을 하나로 묶었습니다. 객체화를 통해 필터 조건을 동적으로 처리할 수 있게 되었고, 더 이상 개별 함수에 필요한 인자를 넣지 않아도 되었습니다.

// 기존 개별 필터링에 **인자 3개씩 전달 
// + id,class명 전달**해주던 코드 대체

const filters = {
  gender: getSelectValue("sel_gender"),
  role: getSelectValue("sel_role"),
  name: getInputName(),
  enName: getInputValue("enNameInput"),
  github: getInputValue("githubInput"),
  week1: getInputNumber("week1Input"),
  week2: getInputNumber("week2Input")
};

 

2. Object.entries()를 사용한 동적 필터링

: 이전 코드에서는 각 필터 함수가 배열을 반복하면서 필터링을 적용했지만, Object.entries(filters) 를 사용하여 filters 객체의 모든 필터 조건을 순회하며 해당 필드와 필터 값을 비교할 수 있도록 구현하였습니다.

// 개별 필터링 대체

const filteredMembers = memberList.filter((member) =>
  Object.entries(filters).every(([key, value]) =>
    !value || member[key]?.toString().includes(value)
  )
);

⭐️ Object.entries(filters)는 filters 객체의 key와 value를 반환하므로, member[key]로 해당 필드의 값을 동적으로 접근가능했습니다! 

Object.entries()

: 키-값 쌍을 배열의 형태로 반환하는 메서드

: 객체 내부의 속성에 대해 쉽게 반복 작업을 가능하게 합니다.

const user = {
	name: 'Mike',
	age: 30,
	gender: 'male',
}

// Object.entries(user)이 반환하는 배열
[ 
		[ name, 'Mike'],
		[ age, 30 ],
		[ gender, 'male']
	]

 

3. includes, 동적 속성 접근

member[key]?.toString().includes(value)

: 이전 코드에서는 각 필드를 명시적으로 지정했지만, 이를 동적으로 접근해보고자 했고 filters 객체의 키가 member[key]로 해당 필드에 동적 접근이 가능해졌습니다.

 

옵셔널 체이닝(?.)

: JS에서 안전하게 객체의 속성에 접근하기 위해 사용된다.

: 객체의 속성이 존재하지 않을 때 에러를 방지하고 undefined를 반환한다.

추가) 옵셔널 체이닝이 필요한 이유

옵셔널 체이닝 '?.'

 

4. 필터를 적용하지 않는 경우도 render.js에서 한번에 처리

(!value) 로 필터 미적용 케이스도 고려하였는데요,

이를 통해 각 유틸함수 상단에 작성했던 다음의 코드를 모두 제거할 수 있었습니다.

  if (value === "") {
    // return memberList;
  }

최종 변경 코드

const filters = {
    gender: getSelectValue("sel_gender"),
    role: getSelectValue("sel_role"),
    name: getInputName(),
    enName: getInputValue("enNameInput"),
    github: getInputValue("githubInput"),
    week1: getInputNumber("week1Input"),
    week2: getInputNumber("week2Input")
  };

  // 필터링 -> 필터가 존재하면 해당 값과 비교, 없으면 통과
  const filteredMembers = memberList.filter((member) =>
    Object.entries(filters).every(([key, value]) => 
      !value || member[key]?.toString().includes(value)
    )
  );

  renderMemberList(filteredMembers); // 필터링된 리스트 렌더링
});

+) 이후 공백, 대소문자 구분 로직 추가했습니다.. 총총...