React

#9 댓글 기능 만들기 part2

Sila 2022. 4. 24. 21:57

지난 번에 이어서 댓글의 수정, 삭제 기능을 구현해보자.

 

1. 댓글 수정

댓글의 내용을 누르면 그게 input element로 바뀌면서 글을 지우고 쓸 수 있게 되고, 이를 제출하면

 

수정한 input box의 내용이 나타나는 방식으로 수정 기능을 구현할 것이다.

 

이를 위해 우선 CommentList 컴포넌트의 {v.content}에 클릭시

 

이를 인식해 클릭한 댓글을 특정해 input box로 바꾸는 기능을 추가한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

import React from 'react'

class CommentList extends React.Component {

    state = {
        value: '',
        update:null
    }
        
    items = () => this.props.list.map((v,k) => {
        return (
            <ul className='comment-row' key={k}>
                <li className='comment-id'>{v.userid}</li>
                
                <li className='comment-content'>
                    {
                        this.state.update === k
                        ? <input type='text' value={this.state.value} className='comment-update-input'/>
                        :
                        <>
                            <span onClick={this.handleClick(k)}>{v.content}</span>
                        </>
                    }
                </li>
                
                <li className='comment-date'>{v.date}</li>
            </ul>
        )
    })
   
    render() {
        return(
            <li>
                {this.items()}
            </li>
        )
    }
}

export default CommentList

 

우선 state를 정의한다.

 

처음에 state.value, state.update의 value는 정해주지 않는다.

 

그리고 items 함수의 comment content를 조건에 따라 바뀌도록 수정한다.

 

위 코드를 해석하자면 li (className='comment-content')의 내용물이

 

state.update의 값이 k라면 input으로,

 

아니면 (null이거나 k가 아닌 다른 값일 경우) 클릭시 handleClick함수가 실행되는 span으로 렌더링된다.

 

이제 댓글 내용이 담긴 span을 클릭하면 state를 바꿔 state.value, state.update의 값을 바꿔주도록

 

handleClick 함수를 짜주면 된다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

handleClick = (i) => (e) => {
    this.setState({
        ...this.state,
        value:e.target.innerHTML,
        update:i
    })
}

 

handleClick 함수는 우선 k값 (k번째 댓글)을 인자값으로 받고, e.target.innerHTML (댓글 내용 span)을 state.value에

 

대입해주는 함수를 실행한다. 함께 받은 k값은 state.update의 값에 대입된다.

 

이 handleClick 함수가 발동함에 따라 staate.update 값이 null에서 k로 바뀌게 되고,

 

그에 따라 span이 input으로 바뀌게 된다. (삼항 연산자의 3항에서 2항으로 변함)

 

여기까지하면 이제 바꾸고 싶은 댓글을 클릭하면 원래 댓글 값을 그대로 전달받은 input으로 바뀐다.

 

 

-----------------------------------------------------

 

 

그런데 여기까지 하고 댓글을 수정하려고 추가적인 입력을 input에 하면 아무것도 안 바뀔텐데,

 

이건 input element에는 state의 변화를 인식하는 함수가 아직 추가되지 않아서 그렇다.

 

여기서도 전 글에서 댓글을 새로 쓸때처럼 state.value를 타이핑에 따라 바꿔주는 함수를 추가해줘야한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

updateChange = (e) => {
    this.setState({
        ...this.state,
        value:e.target.value
    })
}

 

컴포넌트 안에 다음과 같이 state를 바꿔주는 함수를 선언하고, 이를 input element에 추가한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

<input type='text' value={this.state.value} className='comment-update-input'
onChange={this.updateChange}
/>

 

이제 타이핑을 하면 하는대로 input의 value가 바뀌는 것을 확인할 수 있을 것이다.

 

이렇게 작성한 수정된 댓글을 enter키로 submit해보자.

 

1. 우선 엔터가 아닌 다른 키의 경우, submit이 발동되지 말아야 하고,

 

2. 엔터를 눌렀을 때, App 컴포넌트에서 전달받은 list를 깊은 복사한 배열 중

 

내가 수정한 k번째 댓글의 content를 수정한 후,

 

3. state.update를 다시 null로 바꾸고,

 

4. 업데이트된 list를 다시 App 컴포넌트에 전달한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

<input type='text' value={this.state.value} className='comment-update-input'
onChange={this.updateChange}
onKeyDown={this.updateKeyDown(k)}
/>

 

우선 input element에 다음과 같이 KeyDown으로 발동하는 updateKeyDown 함수를 추가한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

updateKeyDown = (i) => (e) => {
    if ( e.key !== 'Enter' ) return
    const newList = [...this.props.list]
    newList[i].content = this.state.value
    
    this.setState({
        ...this.state,
        update:null
    })
}

 

이제 updateKeyDown의 모든 코드가 실행된 후, 업데이트된 새로운 list를 App 컴포넌트에 전달해줘야 한다.

 

이를 위해서는 다시 App 컴포넌트로 돌아가 list가 바뀌었을 때 이를 인식해 state를 바꿔줄 함수를 추가하고

 

CommentForm으로 전달한 후, CommentForm에서 그걸 받아 실행해야 한다.

 

/*  practice/src/App.jsx  */

class App extends React.Component {
// 중략

    updateList = (list) => {
        this.setState({
            ...this.state,
            list
        )}
    }

// 중략

    render() {
        return(
            <>
                <Comment>
                    <CommentForm
                    onSubmit = { (content) => {this.addList(content)} }
                    />
                    <CommentList list={this.state.list}
                    updateList = {this.updateList}
                    />
                </Comment>
            </>
        )
    }
}

 

이 updateList를 CommentForm의 updateKeyDown 함수에서 사용한다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

updateKeyDown = (i) => (e) => {
    if(e.Key !== 'Enter') return
    const { updateList } = this.props
    const newList [...this.props.list]
    newList[i].content = this.state.value
    
    this.setState({
        ...this.state,
        update:null
    })
    
    updateList(newList)
}

 

이렇게하면 엔터를 칠 때, updateList가 호출되어 App 컴포넌트의 list도 업데이트가 된다.

 

 

2. 댓글 삭제

마지막으로 댓글 수정 기능을 구현해보자.

 

우선 클릭시 삭제 함수가 발동할 x버튼을 가진 span을 하나 더 만들어주자.

 

/*  practice/src/component/comment/CommentForm.jsx  */

<>
    <span onClick={this.handleClick(k)}>{v.content}</span>
    <span className='comment-delete-btn' onClick={ () => { this.deleteClick(k) } }>
   	    x
    </span>
</>

 

deleteClick 함수는 다음과 같이 filter를 통해 지운 댓글을 거른 나머지 댓글들로 다시 배열을 만들어

 

updateList 함수를 똑같이 실행하면 된다.

 

/*  practice/src/component/comment/CommentForm.jsx  */

deleteClick = (k) => {
    const { list, updateList } = this.props
    const newList = [...list].filter( (v,i) => i !== k)
    
    updateList(newList)
}

 

댓글을 수정할때나 지울때나 결국 App 컴포넌트에서 state.list를 바뀐 list로

 

갈아껴주는 동일한 과정을 거지는 것이므로 똑같이 updateList 함수를 사용해도 된다.

 

 

 

 

 

 

'React' 카테고리의 다른 글

#11 함수형 컴포넌트 2. useEffect  (0) 2022.04.29
#10 함수형 컴포넌트 1. intro, useState  (0) 2022.04.29
#8 댓글 기능 만들기 part1  (0) 2022.04.24
#7 곱셈 프로그램 만들기  (0) 2022.04.24
#6 Styling  (0) 2022.04.22