Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- react next
- KDT 프로그래머스
- netlify redirect
- 프로그래머스 K_Digital Training
- vue 지역 컴포넌트
- Vue
- 이벤트 수식어
- 프로그래머스 프론트엔드 데브코스
- 프로그래머스 데브코스 프론트엔드
- postcss
- 리액트
- 프로그래머스 데브코스
- SCSS use
- SCSS extend
- 폼 입력 바인딩
- git 같은계정 다른 컴퓨터
- flex
- Spacer
- vue mixin
- SCSS forward
- vue 이벤트 수신
- 고양이 사진 검색기
- intersection opserver
- vuex map
- 리스트 렌더링
- 쌓임맥락
- SCSS import
- nextjs사용법
- 다른컴퓨터에서 git사용
- KDT 프로그래머스 데브코스 프론트엔드
Archives
- Today
- Total
혼자 적어보는 노트
[React] input focus감지 / 영역 밖 클릭 시 이벤트 본문
하고싶었던 기능은
input의 focus를 감지하여 포커스가 되면 최근검색어 창이 띄워지고
검색 시 최근 검색어가 담기며, 지우기버튼을 누르면
최근검색어가 지워지는 기능이였다.
단순 onFocus / onBlur을 사용하여 최근검색어 창의 state를 true/false로 관리하려 시도했지만
focus가 된 상태에서 최근검색어 창을 누르기위해 접근하면 input의 focus가 풀리면서
당연하게도 닫기 버튼이 클릭을 할 수 없는 문제가 발생한다.
focus가 되면 state가 true가되고
focus가 되지 않은 상태에서 최근검색어 영역 밖을 클릭하면 state가 false로 되었으면 했다.
useRef를 이용한 영역 밖 클릭 감지
const clickWrapp = (event) => {
if (document.activeElement !== searchInput.current &&
// searchInput이 focus되지 않았을 경우
!searchWrapp.current.contains(event.target)) {
// ref로 지정한 영역이 event.target을 포함하지 않았을 경우 코드 실행
setSearchState({ ...searchState, searchFocus: false });
}
};
useEffect(() => {
document.addEventListener("click", clickWrapp);
}, []);
useEffect로 document전체의 클릭을 감지하고
document.activeElement !== searchInput.current 를 이용하여 현재 input에 focus가 되어있는지를 확인했다.
해당 조건에 부합하면 searchFocus를 false로 바꾸었다.
전체코드
export default function SearchPopup() {
const searchInput = useRef();
const searchWrapp = useRef();
const history = useHistory();
const initialSearch = {
searchKeyword: "",
searchFocus: false,
};
const [searchState, setSearchState] = useState(initialSearch);
const [historyList, setHistoryList] = useState([]);
const handleFocusOn = () => {
setSearchState({ ...searchState, searchFocus: true });
};
const clickWrapp = (event) => {
if (
document.activeElement !== searchInput.current &&
!searchWrapp.current.contains(event.target)
) {
setSearchState({ ...searchState, searchFocus: false });
}
};
const search = (keyword) => {
console.log("search");
setSearchState({ ...searchState, searchKeyword: keyword });
addHistory(keyword);
};
const addHistory = (keyword) => {
if (!keyword) {
return;
}
const history = { id: createNextId(historyList), keyword };
setHistoryList([history, ...historyList]);
};
const removeHistory = (id) => {
const history = historyList.filter((item) => item.id !== id);
setHistoryList(history);
};
useEffect(() => {
document.addEventListener("click", clickWrapp);
}, []);
return (
<div className="search-area" ref={searchWrapp}>
<form
className="search-form"
onSubmit={(event) => {
event.preventDefault();
search(searchState.searchKeyword);
history.push({
pathname: `/search/${searchState.searchKeyword}`,
});
searchInput.current.value = "";
}}
>
<input
ref={searchInput}
type="text"
onChange={(event) => {
setSearchState({
...searchState,
searchKeyword: event.target.value,
});
}}
onFocus={(event) => handleFocusOn(event)}
/>
<button>검색</button>
</form>
{searchState.searchFocus && (
<div className="search-layer">
<h1>최근검색어</h1>
<ul>
{historyList.length > 0 ? (
historyList.map(({ id, keyword }) => (
<li key={id}>
{keyword}
<button
onClick={(event) => {
removeHistory(id);
}}
>
닫기
</button>
</li>
))
) : (
<span>검색결과가 없습니다 </span>
)}
</ul>
</div>
)}
</div>
);
}
하지만 최근 검색어 창 안의 최근검색어 리스트에 닫기버튼을 부여해주었는데
닫기 버튼을 누르면 리스트에서 삭제되는 기능은 동작하나 닫기 클릭 시 창이 닫아져버린다.
clickWrapp()이 함께 실행되버린 것이다.
<button
onClick={(event) => {
event.stopPropagation();
removeHistory(id);
}}
>
닫기
</button>
버튼의 onClick에 event.stopPropagation()을 넣어 이벤트가 전달되는 것을 막으니 해결되었다.
'React' 카테고리의 다른 글
[React] input warning / defaultValue / readOnly (0) | 2021.12.17 |
---|---|
[React] 비동기 setState 연속 처리 시 오류 (0) | 2021.12.15 |
[React] key를 사용해야하는 이유 (0) | 2021.12.13 |
[React] 비동기 SetState 동기식 처리 (0) | 2021.12.10 |
[React] immer를 사용한 불변성 관리 (0) | 2021.12.09 |
Comments