위코드 2차 프로젝트 Unsplash 클론 프로젝트 중 기억에 남는 코드에 대한 리뷰 글입니다. 💕
const MainSearch = (props) => {
const [searchInput, setSearchInput] = useState("");
const [searchDatas, setSearchDatas] = useState([]);
const [searchResult, setSearchResult] = useState([]);
const [stateSearchModal, setStateSearchModal] = useState(false);
const handleInputChange = (e) => {
const {
target: { value },
keyCode,
} = e;
const filteredTags = searchDatas
.filter((data) => {
const regExp = new RegExp(`^${value}`, "gi");
return data.match(regExp);
})
.slice(0, 5);
> `RegExp`는 정규식 생성자 함수이다. "^"는 줄(line)의 시작에서 일치한다는 의미, "gi"에서 "g"는 global의미로 모든 문자를 검색하겠다는 의미이며 i는 insensitive의미로 영어 대소문자를 구분 않고 일치시키겠다는 의미이다. 그리고 `match` 메소드를 통해
일치하는 문자열의 배열만 반환하고 있다. 그것을 다시 `slice` 메소드로 5개만 가져오고 있다.
출처 : https://heropy.blog/2018/10/28/regexp/
value.length && keyCode === 13 && props.history.push(`/photo/${value}`); // 입력하는 value 값이 있고
엔터키를 쳤을 때 해당 페이지로 이동
setSearchResult(value.length ? filteredTags : []);
// 입력하는 value값이 있다면 필터시킨 태그들을 넣고 아니면 빈배열을 넣어라
setStateSearchModal(value.length);
// 입력하는 value값이 있을 시 추천태그 모달창이 뜨게 한다.
setSearchInput(value);
};
const clickFilter = (which) => {
which === "size"
? setStateFilterSize(!stateFilterSize)
: setStateFilterColor(!stateFilterColor);
};
(중략)
<div
tabindex="0"
onFocus={() => clickFilter("size")}
onBlur={() => clickFilter("size")}
className="filterBox size"
name="size"
>
인자로 size,color를 전달하여 해당 div 클릭 시 변경된 state 상태값이 props전달 되고 visiblity 속성을 활용해 해당 모달창이 보이게 만들었다
visibility: ${(props) => (props.visibility ? "visible" : "hidden")};
여기서
tabindex
는
const clickSizeInfo = (which) => {
setSizeInfo(which);
setSizeData(
cards.filter(({ width, height }) => {
if (which === "Landscape") {
return height < width;
}
if (which === "portrait") {
return height > width;
}
if (which === "square") {
return height === width;
}
})
);
};
(중략)
<span>{sizeInfo}</span> // Landscape, portrait, square를 인자로 전달하여 그 인자를 값으로 받는다.
<GoTriangleDown />
</Filter>
<FilterSizeResult visibility={stateFilterSize}>
<li>Any orientation</li>
<li onClick={() => clickSizeInfo("Landscape")}>
<DivBox className="landscape" />
<p>Landscape</p>
</li>
<li onClick={() => clickSizeInfo("portrait")}>
<DivBox className="portrait" />
<p>Portrait</p>
</li>
<li onClick={() => clickSizeInfo("square")}>
<DivBox className="square" />
<p>Square</p>
</li>
</FilterSizeResult>
fetch
로 전달받는 데이터를cards
에 넣고 그 데이터를 필터한다. 위에서 인자로 전달한 조건에 따라 리턴값을 다르게 설정해filter
기능을 구현했다.
<div
tabindex="1"
onFocus={() => clickFilter("size")}
onBlur={() => clickFilter("size")}
className="filterBox size"
name="size"
>
div,span의 경우 button, input과 달리 focus가 먹지 않는다는 것을 알았다. 위 태그에 불가피하게 focus를 줘야 할 경우
tabindex
를 줄 수 있다.
The tabindex global attribute indicates that its element can be focused, and where it participates in sequential keyboard navigation (usually with the Tab key, hence the name).
tabindex란? 그것의 속성이 연속적인 키보드 움직임에 따라
focused
될 수 있는 것을 뜻한다
1) tabindex="1"
문서 안에서 가장 먼저 초점을 받을 수 있습니다. 그러나 자연스러운 마크업 순서를 거스르기 때문에 주의해서 사용해야 합니다. 검색엔진 사이트에서 검색창에 사용하면 적합하지만(이 대신 autofocus 속성이 더 적절할 듯 해요) 그 외 적합한 경우는 잘 떠오르지 않는군요.
2) tabindex="0"
키보드 초점을 받을 수 없는 div, span과 같은 요소도 초점을 받을 수 있도록 만들어 줍니다. 초점을 받되 초점을 받는 순서는 자연스러운 마크업 순서를 따릅니다.
3) tabindex="-1"
키보드 초점을 받을 수 있는 요소도 초점을 받을 수 없도록 만들어 줍니다. 초점을 받을 수 없기 때문에 "-1" 이외의 다른 음의 정수 값은 사실상 의미가 없습니다.
나의 경우에 tabindex="1" 줬지만 위 설명에 따르면 0을 주는 것이 적절하다.