const [hasText, setHasText] = useState(false);
const [inputValue, setInputValue] = useState("");
const [options, setOptions] = useState(deselectedOptions);
hasText
: text가 들어오는 input창에 값이 들어왔는지 아닌지, 값의 유무를 갖는 상태
inputValue
: input창에 들어온 값을 갖는 상태
options
: input값을 포함하는 자동완성 추천 항목 리스트 (초기값으로 dummy data? 이미 추천 항목들의 집합인 배열 'deselectedOptions'가 주어짐 )
useEffect(() => {
if (inputValue === "") {
setHasText(false);
} else {
setHasText(true);
}
}, [inputValue]);
과제에서 useEffect를 이용해 inputValue가 바뀔 때마다 리렌더링 되도록 해줌.
const handleInputChange = (value) => {
setInputValue(value);
let filteredOptions = deselectedOptions.filter((el) => {
return el.toUpperCase().includes(value.toUpperCase());
});
if (filteredOptions.length) {
//필터링을 했는데 아무런 추천 검색어도 나오지 않았을 경우를 따로 빼주어야 함
setOptions(filteredOptions);
} else {
setOptions([]);
}
};
const handleDropDownClick = (textCon) => {
//input 태그의 vlue 속성의 값으로 inputValue를 지정해놓는 것이 keypoint인데
//그렇게 하지 않으면 이 파일 내부에서 사용하는 inputValue라는 상태와 input 요소의 value 값을 따로 생각해주어야 했음.
//그렇게 될 경우 useRef를 사용해야 함.
//inputEl이 input의 주소값이면
//inputEl.current.value = textCont; 처럼 따로 input의 value를 지정해줬어야 한다는 말.
//아래 delete 핸들러에서도 input.current.value = "";와 같이 써주어야 함.
//useRef는 가능하면 덜 쓰는 편이 좋으므로... 지양하자.
handleInputChange(textCon);
};
//매개변수 textCon은 li 태그 속 onClick이 아래와 같이 li의 textContent를 받기 때문에 그렇게 씀
//
//onClick = {((e)=>{handleDropClick(e.target.textContent)})}
const handleDeleteButtonClick = () => {
setInputValue("");
};
handleInputChange
: input에서 onChange 이벤트 시 실행되며, 이벤트 발생 시, 이벤트가 일어난 input에서 value를 받아와서 inputValue의 값을 변화시키고, value 값을 포함한 추천 검색어들을 deselectedOptions에서 필터링하도록 한다. (options 상태의 변화)
handleDropDownClick
: 추천 항목 리스트(li들)에서 한 항목을 클릭할 때 = onClick 이벤트가 발생할 때 실행되는 이벤트 핸들러로, 클릭한 항목의 textContent가 inputValue가 되어야 함.
사실 그렇게 inputValue가 변화하게 되면, 연결되어 있는 options 상태도 함께 변화하므로 잘 생각해보면 handleDropDownClick 핸들러 내부에서 handleInputChange를 실행시켜주면 된다는 것을 알 수 있다.
handleDeleteButtonClick
: input 창 오른쪽의 X버튼에서 onClick 이벤트가 일어나면 실행되는 이벤트 핸들러로, inputValue의 값을 빈 문자열로 만들어주어야 한다.
isEditMode
: 수정이 가능한 상태인지를 담고 있음 (boolean)
newValue
: input에 값이 입력되면 실제로 보이게 될 값
useEffect(() => {
if (isEditMode) {
inputEl.current.focus();
}
}, [isEditMode]);
//isEditMode라는 키워드의 값이 변경될 때마다 새로고침을 해주기 위해 사용 (원래는 사이드 이펙트 관리용 )
//focus의 사용을 위함
//inputEl은 useRef로 input의 주소값을 가진 변수임
useEffect(() => {
setNewValue(value);
}, [value]);
const handleClick = () => {
setEditMode(!isEditMode);
};
const handleBlur = () => {
setEditMode(!isEditMode);
handleValueChange(newValue);
};
//handleValueChange는 props로 받아온 것
//위 state들과 handler function들은 MyInput이라는 엘리먼트에 포함되어 있고,
//MyInput엘리먼트는 ClickToEdit이라는 엘리먼트의 하위 엘리먼트.
//ClickToEdit에서 MyInput으로 value와 handleValueChange를 Props로 전달했음.
const handleInputChange = (e) => {
setNewValue(e.target.value);
};
handleClick
: isEditMode 상태를 변경하는 이벤트 핸들러
handleBlur
: onBlur라는 이벤트 핸들러를 이용해 input칸이 아닌 나머지 칸을 클릭했을 때는 input칸을 수정할 수 없는 상태로 만든다.
handleInputChange
: 저장된 value를 업데이트 하도록 함
: 우선 함수의 실행 자체를 이벤트 속성에 넣어주는 경우에는 컴퓨터가 파일을 읽는 과정에서 함수를 즉각적으로 실행시켜버리고, 그 뒤로 해당 이벤트가 실행될 때는 'undefined'가 출력될 뿐이므로 일단 절대로 함수 실행을 전달해서는 안 된다!
onClick = {handleClick()}//❌❌❌
콜백 함수로 (익명 함수로) 전달하는 경우에는 실행시키고자 하는 이벤트 핸들러 함수를 중괄호 안에서 실행되도록 전달할 수 있다. 이때, 이 이벤트 핸들러 함수는 ⭐️매개변수를 갖는다. ⭐️
onClick = {(e)=> {handleClick(e.target.value)}}
//매개변수가 실행된 이벤트의 타켓의 value인 경우
onCLick = {()=>{handleClick("hi")}}
//매개변수의 전달인자가 문자열 "hi"
그냥 함수 자체를 넘겨주는 경우는 아래와 같다.
이벤트 핸들러 함수로 어떤 ⭐️매개변수를 넘겨줄 필요가 없을 때⭐️ 아래와 같이 사용한다.
이벤트 객체 외에는 다른 매개변수가 없는 경우로, handleClick 함수에서는 아래와 같이 이벤트 객체를 받아올 수 있으나, 그 외 다른 매개변수는 없다.
const handleClick = (e) => {
console.log(e);
}
<button onClick = {handleClick}></button>
여태 많은 페어들을 만났지만 오늘 페어분은 특히나 설명을 잘 해주신다고 느낀 것 같다.
어떤 기능에 대해 설명할 때, 왜 이것을 사용하며, 원리가 어떠하다는 것을 짚어주셨고, 특히나 본인이 직접 경험해본 내용을 함께 이야기해주셔서 이해하기가 정말 좋았다.
페어 프로그래밍을 할 때 다른 사람에게 설명하는 것이 얼마나 중요한 공부 기회인지 알기 때문에 나 역시 단어도 신경쓰고, 왜 그런지 설명하려고 노력하는 편인데 내가 원하는 만큼 설명한다면 이분 같겠구나 ~ 하는 생각을 했달까.