티스토리 뷰
문제
Input 검색창에서 검색을 한 후 검색어 저장하는 기능이 있었다.
정확히 말하면 최대 5개까지만 검색어 저장을 하고, 저장되어 있는 검색어를 또 검색했다면 마지막으로 오게 하는 기능이다.
그런데 문제없이 잘 작동한 줄 알았는데, 나중에 확인해보니 검색어 저장이 6개까지 되고, 7개째 오류가 발생했다.
아래는 오류가 났을 때 코드이다.
// input은 검색어
// const [records, setRecord] = useState([]);
const onSubmitForm = () => {
//...
setRecord(records.filter((item) => item !== input).concat(input));
if (records.length > 5) setRecord(records.shift());
}
함수 내부 코드에서
1번째줄: 중복된 검색어를 filter를 사용하여 제거하고, 마지막에 검색어를 추가해서 records를 업데이트하는 로직이다.
2번째줄: 길이가 6개 이상이면 records의 가장 왼쪽(처음)의 원소를 제거하여 records를 업데이트하는 로직이다.
문제 해결1
가장 먼저 발견한 것은 shift()메서드이다
shift()메서드를 사용하지 못하는데, 이유는 shift()메서드는 가변 메서드이기 때문이다.
(가변 메서드: 원본에 직접 변화를 주는 메서드)
구체적으로 말하면 리액트는 상태 변화에 가변 메서드가 아닌 불변 메서드만 사용할 수 있다.
이유는 리액트는 원본 DOM에 직접 영향을 끼치는게 아니고, Virtual DOM(가상 DOM)을 사용하여 가상 DOM에 변화를 적용한 후, 원본 DOM과 Virtual DOM의 차이점만 비교를 해 그 부분을 업데이트 하는 것이다.
따라서 상태 변화에 불변 메서드만 사용할 수 있어서, 아래와 같이 slice()메서드를 사용해서 코드를 수정했다.
// input은 검색어
// const [records, setRecord] = useState([]);
const onSubmitForm = () => {
//...
setRecord(records.filter((item) => item !== input).concat(input));
if (records.length > 5) setRecord(records.slice(1));
}
문제 해결2
그런데 아직도 검색어 저장이 자꾸 6개가 되는 것이였다.
원인을 찾았는데 바로 useState()는 비동기 처리가 되는 것이였다.
위의 코드로 설명을 하자면
1. setRecord(records.filter((item) => item !== input).concat(input));
2. if (records.length > 5) setRecord(records.slice(1));
(동기) 1번 코드가 끝나야 2번 코드가 실행되는 것이 아니고,
(비동기) 1번 코드가 끝나기 전에 2번 코드가 실행된다.
예를 들면, records(검색어)가 5개 있을 때, 1번 코드에서 1개를 추가해서 6개가 되기 전에, 2번 코드가 실행되서 records(5개)로 인식되어 조건문에 맞지 않아서, 결국 검색어 6개가 나왔던 것 같다.
따라서 아래와 같이 코드를 수정해서 해결했다.
// input은 검색어
// const [records, setRecord] = useState([]);
const onSubmitForm = () => {
//...
if (records.length < 5) {
setRecord(records.filter((item) => item !== input).concat(input));
} else
setRecord(records.filter((item) => item !== input).concat(input).slice(1));
}
또한 useState가 비동기 처리가 되는지 확실하게 넘어가고 싶어서 한번 더 확인을 했다.
console.log(records);
setRecord(records.filter((item) => item !== input).concat(input));
console.log(records);
만약 동기적으로 작동한다면 콘솔에 찍히는 records는 다르게 나올 것이고, 비동기적으로 작동한다면 콘솔에 찍히는 records는 똑같이 나올 것이다.
결국 콘솔에 찍히는 records는 똑같이 나왔다.
'프론트엔드' 카테고리의 다른 글
웹팩의 빠른 로딩 속도 비교하기 (0) | 2022.08.11 |
---|---|
useRef와 useState의 변화에 따른 렌더링 차이 (0) | 2022.08.07 |
PR에서 테스팅 후 성공시에만 자동 Merge하기 (0) | 2022.08.03 |
www.naver.com을 입력했을 때 일어나는 일 (0) | 2022.06.15 |
Javascript엔진, 이벤트 루프 (0) | 2022.06.11 |
- Total
- Today
- Yesterday