하....잘하다가 막판에 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