하....잘하다가 막판에 cancel 버튼 (X버튼) 때문에 좀 힘들었다😭
왜 막혔는지랑 어떻게 해결했는지는 밑에서 정리하고, 일단 검색창 코드부터 gogo!
this.state = {
searchClick: false,
searchInput: '',
};
일단 초기 state 에 searchClick , searchInput 값을 지정해준다.
searchOnHandler = () => { // onFocus 이벤트
this.setState({ searchClick: true });
};
searchOffHandler = () => { // onBlur 이벤트
this.setState({ searchClick: false });
};
setSearchHandler = (e) => { // input 창에 onChange 이벤트
this.setState({
searchInput: e.target.value,
});
};
이벤트는 searchClick 이라는 상태만 true/false 로 계속 변경해주고,
css에서 포커스 됐을때와, 포커스를 잃었을때의 검색창 디자인 2가지를 만들어준다.
그리고 각 input창이나 icon 의 className 에서 삼항연산자를 이용해서 searchClick 상태에 따라 변경될 수 있게 했다.
처음에는 이런식으로 했었다!
<div> // onFocus, onBlur 이벤트
<img search_icon/>
<button cancel_icon/>
<input 검색창/> // onChange 이벤트
</div>
이렇게 걸어주니까 잘 동작했는데...
찐스타그램을 보면
X버튼을 클릭했을때, 다시 클릭하기전 검색창으로 돌아간다.
나는 안돌아간다. 돌아가게 만들어 줘야지!
에서부터 이제 문제의 cancel 버튼 뜯어고치기 여정이 시작된다...........ㅠ
댓글창과 마찬가지로,
searchInputRemoveHandler = () => {
this.setState({
searchInput: '',
searchClick: false,
});
};
처음 검색창으로 돌아갈 수 있도록 searchClick의 상태를 바꿔주고, input value를 지워주는 이벤트를 하나 만들었다.
input 창에 value={this.state.searchInput} 를 지정해주고, X 버튼에 onClick 이벤트를 걸어주었는데.....
문제는 X버튼이 onFocus, onBlur 이벤트가 걸린 div 보다 하위에 있어서, 버튼이 눌리지 않는 것이다ㅠㅠ
(그러니까 버튼이 눌리기 전에, input 창 바깥이 먼저 클릭되서 onBlur 이벤트가 먼저 실행되어 버리고, X버튼은 없어진다......)
결국 종택님께 도움 요청 ㅠㅠㅠㅠㅠㅠㅠㅠ
여러가지 방법이 있지만 종택님 본인이라면 cancel_icon 을 상단으로 뺄거라고 하심!
<div 새로만듬>
<button cancel_icon/>
<div>
<img search_icon/>
<input 검색창/>
</div>
</div>
이렇게 구조를 변경해줬다.
근데 이번엔 X 버튼이 보이지 않는 문제가....!!
다시 종택님께 달려갔더니, .cancel_icon 의 css에 이런 속성을 추가해주셨다.
z-index: 100;
( z-index의 값이 항상 100이어야 하는건 아니다. 양의 정수이기만 하면 됨)
💁🏻♀️
z-index란?
엘리멘트들이 어떻게 쌓이는지 결정하는 속성이다.
여기서 쌓인다는 의미는 엘리멘트들이 어떻게 포개지는지를 말한다.
포토샵의 레이어를 생각하면 쉽다. 숫자가 낮을수록 하위 레이어, 높을수록 상위 레이어다.
단,z-index는position속성이 설정된 엘리먼트에 대해서만 동작한다.
왜? 그야,position속성으로 겹치는게 아니라면, 엘리멘트들이 겹쳐질 일이 없으니까!!!
이런 느낌임!
그러니까 즉, X버튼은 안보였던 게 아니라 위의 input 창에 포개져서 안보였던것...!!
z-index 주니까 해결되었다!

이렇게 동작한다!
인스타그램에서 좋아요 버튼을 누르면 빨갛게 칠해지면서 살짝 커졌다가 작아진다.
그부분을 구현해보기로!!!
constructor(props) {
super(props);
this.state = {
btn_color: true,
};
}
btnChangeHandler = () => {
this.setState({ btn_color: !this.state.btn_color });
};
state 초기 설정할 때, btn_color 라는 key 에 true 라는 값을 할당해준다!
btnChangeHandler 라는 이벤트는 click 이벤트로 걸어주고, 요 아이는 클릭할 때 마다 true/false 값을 바꿔주는 역할을 한다!
그 후에, 클릭할 때 마다 boolean 값이 바뀌는 요 this.state.btn_color 라는 녀석을 여기저기 다 이용해주면 된다!!
일단 css에 버튼 스타일을 2개 만들어놓고,
className={this.state.btn_color ? 'off_button' : 'on_button'}
요렇게 하트가 눌릴때 마다 class가 변경될 수 있도록 해주었다!
참고로, css에서
@keyframes도 같이 걸어서,0%100%에서는width:100%로,50%에서는width:125%정도로 애니메이션을 걸어주었다.
찐스타그램에서 보니까 path 자체도 바뀌어서 (테두리만 있는 하트, 꽉 찬 하트) className 변경할때랑 같은 방식으로 path 값도 바꿔주었다!

이렇게 동작함😘!!!!
<div className='more_comment'>
<a href=''>댓글 {this.state.commentArr.length + 2}개 모두 보기</a>
</div>
그리고 댓글 2개 모두 보기 부분이 그때그때 바뀔 수 있도록 this.state.commentArr.length + 2 를 넣어주면 끝!! 간단쓰~~~
+ 2는 먼저 댓글단 두 분이 있어서ㅋㅋㅋㅋㅋ넣었음

이렇게 댓글이 하나씩 늘어난다!!!
지옥의 댓글 삭제......😅
Uploadcomment component 에 아래와 같은 이벤트를 추가해준다.
commentDelHandler = (index) => {
this.setState({
commentArr: this.state.commentArr.filter((_, idx) => idx !== index),
});
};
commentDelHandler 라는 함수는 index 를 파라미터로 받아 오는데, 이 index 는 아래에서 map 돌면서 댓글을 계속 추가해주는 <CommentForm /> 의 index 를 말한다.
commentArr 의 값을 commentArr 에 filter 돌린 값으로 setState 해준다.
이 filter 는 _ ( commentArr 의 요소인데, 안쓸거라서 _ 라고 썼음. idx 는 filter 메서드의 2번째 파라니터인데, 해당 배열의 index 값을 의미한다.)
즉, commentArr 의 idx(index)가 <CommentForm /> 의 index 와 일치하지 않은 것만 반환하여 commentArr 를 setState 해주는 것!!
이제 아래에서 댓글을 클릭 할때마다 <CommentForm /> 의 index 값을 받아와서, commentArr 의 idx = 등록되어 있는 댓글 과 <CommentForm /> 의 index = 유저가 click한 댓글 의 index의 일치여부를 commentDelHandler 함수로 확인할거당!!
만약 인덱스가 일치하면? 그 댓글만 삭제하면 된다! 삭제는 어떻게 구현할까?
filter 를 이용하면 테스트를 통과한 댓글만 다시 반환해주니까, idx !== index 이라고 쓰면된다.
(idx === index 만 삭제랑 같다!)
map 으로 돌리는 component에 props로 해당 이벤트를 넘겨준다.
{this.state.commentArr.map((userInput, idx) => (
<CommentForm name='Wecoder' comment={userInput} key={idx} index={idx} commentDelHandler={this.commentDelHandler} />
))}
나는 삭제 버튼을 따로 만들지 않고 (안예뻐서....)
그냥 댓글 내용을 클릭하면 바로 댓글이 삭제 되도록 아래의 위치에 이벤트를 걸었다.
CommentForm
<span onClick={() => this.props.commentDelHandler(this.props.index)}>{this.props.comment}</span>
고작 한줄인데 무지 어렵다.
대충 뭔말이냐면.... onClick 때 이벤트가 실행되는데.... 그 이벤트는 Uploadcomment 에서 props로 넘겨준 이벤트다.
근데 이 이벤트는, 함수이므로, 인자를 받을 수 있다.
CommentForm 에서 map으로 돌리는 <Component index={idx} /> 의 저기 저녀석!!!!
index를 인자로 넘겨준다.
(여기서 이 index 는 실제로는 map 함수의 두번째 인자로서, 자동으로 뽑아내지는 댓글의 index이다.)
arrow function으로 넘겨준 이유는 댓글을 click 해야지만 함수가 실행될 수 있도록, 콜백 함수로 넘겨준것이다.
이부분 아직 많이 헷갈려서 다시 진행 순서를 정리해보았다.
파라미터로
index를 받는commentDelHandler함수 정의(이하Del) →<CommentForm />한테 props로Del함수 전달 →<CommentForm />에서Del함수 전달 받아서,<span>태그 안에onClick이벤트로Del함수 전달 (이 때 형태는 콜백 함수) →<CommentForm />의index를 props로Del함수의 인자로 넘겨준다!
이렇게 댓글을 클릭하면 삭제된다!
진짜 끝!!!!!!!!!!!!1
